Реализован UI файлов, звонков и аватаров в пузырьках сообщений — Telegram iOS parity

This commit is contained in:
2026-03-29 01:57:45 +05:00
parent 16191ef197
commit 6e927f8871
25 changed files with 1354 additions and 296 deletions

View File

@@ -0,0 +1,240 @@
import XCTest
@testable import Rosetta
@MainActor
final class CallSoundAndTimeoutTests: XCTestCase {
private let ownKey = "02-own-sound-test"
private let peerKey = "02-peer-sound-test"
override func setUp() {
super.setUp()
CallManager.shared.resetForSessionEnd()
CallManager.shared.bindAccount(publicKey: ownKey)
}
override func tearDown() {
CallManager.shared.resetForSessionEnd()
super.tearDown()
}
// MARK: - Ring Timeout Tests
func testRingTimeoutTaskCreatedOnOutgoingCall() {
let result = CallManager.shared.startOutgoingCall(
toPublicKey: peerKey,
title: "Peer",
username: "peer"
)
XCTAssertEqual(result, .started)
XCTAssertNotNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be set for outgoing call")
XCTAssertEqual(CallManager.shared.uiState.phase, .outgoing)
}
func testRingTimeoutTaskCreatedOnIncomingCall() {
let packet = PacketSignalPeer(
src: peerKey,
dst: ownKey,
sharedPublic: "",
signalType: .call,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(packet)
XCTAssertNotNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be set for incoming call")
XCTAssertEqual(CallManager.shared.uiState.phase, .incoming)
}
func testRingTimeoutCancelledOnAcceptIncoming() {
// Set up incoming call
let packet = PacketSignalPeer(
src: peerKey,
dst: ownKey,
sharedPublic: "",
signalType: .call,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(packet)
XCTAssertNotNil(CallManager.shared.ringTimeoutTask)
// Accept
_ = CallManager.shared.acceptIncomingCall()
XCTAssertNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be cancelled on accept")
}
func testRingTimeoutCancelledOnDeclineIncoming() {
let packet = PacketSignalPeer(
src: peerKey,
dst: ownKey,
sharedPublic: "",
signalType: .call,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(packet)
XCTAssertNotNil(CallManager.shared.ringTimeoutTask)
CallManager.shared.declineIncomingCall()
XCTAssertNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be cancelled on decline")
XCTAssertEqual(CallManager.shared.uiState.phase, .idle)
}
func testRingTimeoutCancelledOnEndCall() {
_ = CallManager.shared.startOutgoingCall(
toPublicKey: peerKey,
title: "Peer",
username: "peer"
)
XCTAssertNotNil(CallManager.shared.ringTimeoutTask)
CallManager.shared.endCall()
XCTAssertNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be cancelled on endCall")
}
func testRingTimeoutCancelledOnBusySignal() {
_ = CallManager.shared.startOutgoingCall(
toPublicKey: peerKey,
title: "Peer",
username: "peer"
)
XCTAssertNotNil(CallManager.shared.ringTimeoutTask)
let busyPacket = PacketSignalPeer(
src: "",
dst: "",
sharedPublic: "",
signalType: .endCallBecauseBusy,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(busyPacket)
XCTAssertNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be cancelled on busy signal")
XCTAssertEqual(CallManager.shared.uiState.phase, .idle)
}
func testRingTimeoutCancelledOnPeerEndCall() {
let incomingPacket = PacketSignalPeer(
src: peerKey,
dst: ownKey,
sharedPublic: "",
signalType: .call,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(incomingPacket)
XCTAssertNotNil(CallManager.shared.ringTimeoutTask)
let endPacket = PacketSignalPeer(
src: "",
dst: "",
sharedPublic: "",
signalType: .endCall,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(endPacket)
XCTAssertNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be cancelled when peer ends call")
XCTAssertEqual(CallManager.shared.uiState.phase, .idle)
}
// MARK: - Sound Flow Tests (verify phase transitions trigger correct states)
func testOutgoingCallSetsCorrectPhaseForSounds() {
let result = CallManager.shared.startOutgoingCall(
toPublicKey: peerKey,
title: "Peer",
username: "peer"
)
XCTAssertEqual(result, .started)
XCTAssertEqual(CallManager.shared.uiState.phase, .outgoing)
// playCalling() should have been called (verified by phase)
}
func testIncomingCallSetsCorrectPhaseForSounds() {
let packet = PacketSignalPeer(
src: peerKey,
dst: ownKey,
sharedPublic: "",
signalType: .call,
roomId: ""
)
CallManager.shared.testHandleSignalPacket(packet)
XCTAssertEqual(CallManager.shared.uiState.phase, .incoming)
// playRingtone() should have been called (verified by phase)
}
func testCallActiveTransitionClearsTimeout() {
CallManager.shared.testSetUiState(
CallUiState(
phase: .webRtcExchange,
peerPublicKey: peerKey,
statusText: "Connecting..."
)
)
// Manually set timeout to verify it gets cleared
CallManager.shared.startRingTimeout()
XCTAssertNotNil(CallManager.shared.ringTimeoutTask)
CallManager.shared.setCallActiveIfNeeded()
XCTAssertEqual(CallManager.shared.uiState.phase, .active)
XCTAssertNil(CallManager.shared.ringTimeoutTask, "Ring timeout should be cancelled when call becomes active")
}
// MARK: - Duplicate Call Prevention
func testCannotStartSecondCallWhileInCall() {
_ = CallManager.shared.startOutgoingCall(
toPublicKey: peerKey,
title: "Peer",
username: "peer"
)
let result = CallManager.shared.startOutgoingCall(
toPublicKey: "02-another-peer",
title: "Another",
username: "another"
)
XCTAssertEqual(result, .alreadyInCall)
XCTAssertEqual(CallManager.shared.uiState.peerPublicKey, peerKey, "Original call should not be replaced")
}
func testCannotAcceptWhenNotIncoming() {
_ = CallManager.shared.startOutgoingCall(
toPublicKey: peerKey,
title: "Peer",
username: "peer"
)
let result = CallManager.shared.acceptIncomingCall()
XCTAssertEqual(result, .notIncoming)
}
// MARK: - CallsViewModel Filter Tests
func testCallLogDirectionMapping() {
// Outgoing with duration > 0 = outgoing
XCTAssertFalse(CallLogDirection.outgoing.isMissed)
XCTAssertTrue(CallLogDirection.outgoing.isOutgoing)
XCTAssertFalse(CallLogDirection.outgoing.isIncoming)
// Incoming with duration > 0 = incoming
XCTAssertFalse(CallLogDirection.incoming.isMissed)
XCTAssertFalse(CallLogDirection.incoming.isOutgoing)
XCTAssertTrue(CallLogDirection.incoming.isIncoming)
// Duration 0 + incoming = missed
XCTAssertTrue(CallLogDirection.missed.isMissed)
XCTAssertTrue(CallLogDirection.missed.isIncoming)
// Duration 0 + outgoing = rejected
XCTAssertFalse(CallLogDirection.rejected.isMissed)
XCTAssertTrue(CallLogDirection.rejected.isOutgoing)
}
}