253 lines
9.9 KiB
Swift
253 lines
9.9 KiB
Swift
import Testing
|
|
@testable import Rosetta
|
|
|
|
// MARK: - Push Notification Extended Tests
|
|
|
|
struct PushNotificationExtendedTests {
|
|
|
|
@Test("Realistic FCM token with device ID round-trip")
|
|
func fcmTokenWithDeviceIdRoundTrip() throws {
|
|
// Real FCM tokens are ~163 chars
|
|
let fcmToken = "dQw4w9WgXcQ:APA91bHnzPc5Y0z4R8kP3mN6vX2tL7wJ1qA5sD8fG0hK3lZ9xC2vB4nM7oP1iU8yT6rE5wQ3jF4kL2mN0bV7cX9sD1aF3gH5jK7lP9oI2uY4tR6eW8qZ0xC"
|
|
var packet = PacketPushNotification()
|
|
packet.notificationsToken = fcmToken
|
|
packet.action = .subscribe
|
|
packet.tokenType = .fcm
|
|
packet.deviceId = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop"
|
|
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.notificationsToken == fcmToken)
|
|
#expect(decoded.action == .subscribe)
|
|
#expect(decoded.tokenType == .fcm)
|
|
#expect(decoded.deviceId == "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop")
|
|
}
|
|
|
|
@Test("Realistic VoIP hex token round-trip")
|
|
func voipTokenWithDeviceIdRoundTrip() throws {
|
|
// PushKit tokens are 32 bytes = 64 hex chars
|
|
let voipToken = "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
|
|
var packet = PacketPushNotification()
|
|
packet.notificationsToken = voipToken
|
|
packet.action = .subscribe
|
|
packet.tokenType = .voipApns
|
|
packet.deviceId = "device-xyz-123"
|
|
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.notificationsToken == voipToken)
|
|
#expect(decoded.tokenType == .voipApns)
|
|
}
|
|
|
|
@Test("Long token (256 chars) round-trip — stress test UInt32 string length")
|
|
func longTokenRoundTrip() throws {
|
|
let longToken = String(repeating: "x", count: 256)
|
|
var packet = PacketPushNotification()
|
|
packet.notificationsToken = longToken
|
|
packet.action = .subscribe
|
|
packet.tokenType = .fcm
|
|
packet.deviceId = "dev"
|
|
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.notificationsToken == longToken)
|
|
#expect(decoded.notificationsToken.count == 256)
|
|
}
|
|
|
|
@Test("Unicode device ID with emoji and Cyrillic round-trip")
|
|
func unicodeDeviceIdRoundTrip() throws {
|
|
let unicodeId = "Телефон Гайдара 📱"
|
|
var packet = PacketPushNotification()
|
|
packet.notificationsToken = "token"
|
|
packet.action = .subscribe
|
|
packet.tokenType = .fcm
|
|
packet.deviceId = unicodeId
|
|
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.deviceId == unicodeId)
|
|
}
|
|
|
|
@Test("Unsubscribe action round-trip for both token types",
|
|
arguments: [PushTokenType.fcm, PushTokenType.voipApns])
|
|
func unsubscribeRoundTrip(tokenType: PushTokenType) throws {
|
|
var packet = PacketPushNotification()
|
|
packet.notificationsToken = "test-token"
|
|
packet.action = .unsubscribe
|
|
packet.tokenType = tokenType
|
|
packet.deviceId = "dev"
|
|
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.action == .unsubscribe)
|
|
#expect(decoded.tokenType == tokenType)
|
|
}
|
|
|
|
private func decode(_ packet: PacketPushNotification) throws -> PacketPushNotification {
|
|
let data = PacketRegistry.encode(packet)
|
|
guard let result = PacketRegistry.decode(from: data),
|
|
let decoded = result.packet as? PacketPushNotification
|
|
else { throw TestError("Failed to decode PacketPushNotification") }
|
|
#expect(result.packetId == 0x10)
|
|
return decoded
|
|
}
|
|
}
|
|
|
|
// MARK: - Signal Peer Call Flow Tests
|
|
|
|
struct SignalPeerCallFlowTests {
|
|
|
|
@Test("Incoming call signal with realistic secp256k1 keys")
|
|
func incomingCallSignalRoundTrip() throws {
|
|
let caller = "02a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
|
|
let callee = "03f0e1d2c3b4a5968778695a4b3c2d1e0f9e8d7c6b5a49382716051a2b3c4d5e6f"
|
|
let packet = PacketSignalPeer(src: caller, dst: callee, sharedPublic: "",
|
|
signalType: .call, roomId: "")
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.signalType == .call)
|
|
#expect(decoded.src == caller)
|
|
#expect(decoded.dst == callee)
|
|
#expect(decoded.sharedPublic == "")
|
|
#expect(decoded.roomId == "")
|
|
}
|
|
|
|
@Test("Key exchange with X25519 public key")
|
|
func keyExchangeRoundTrip() throws {
|
|
let x25519Key = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
|
|
let packet = PacketSignalPeer(src: "02src", dst: "02dst", sharedPublic: x25519Key,
|
|
signalType: .keyExchange, roomId: "")
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.signalType == .keyExchange)
|
|
#expect(decoded.sharedPublic == x25519Key)
|
|
#expect(decoded.roomId == "")
|
|
}
|
|
|
|
@Test("Create room with UUID room ID")
|
|
func createRoomRoundTrip() throws {
|
|
let roomId = "550e8400-e29b-41d4-a716-446655440000"
|
|
let packet = PacketSignalPeer(src: "02src", dst: "02dst", sharedPublic: "",
|
|
signalType: .createRoom, roomId: roomId)
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.signalType == .createRoom)
|
|
#expect(decoded.roomId == roomId)
|
|
#expect(decoded.sharedPublic == "")
|
|
}
|
|
|
|
@Test("endCallBecauseBusy short format — 3 bytes wire size, no src/dst")
|
|
func endCallBusyShortFormat() throws {
|
|
let packet = PacketSignalPeer(src: "ignored", dst: "ignored", sharedPublic: "ignored",
|
|
signalType: .endCallBecauseBusy, roomId: "ignored")
|
|
let data = PacketRegistry.encode(packet)
|
|
// Short form: 2 bytes packetId + 1 byte signalType = 3 bytes
|
|
#expect(data.count == 3)
|
|
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.signalType == .endCallBecauseBusy)
|
|
#expect(decoded.src == "")
|
|
#expect(decoded.dst == "")
|
|
}
|
|
|
|
@Test("endCallBecausePeerDisconnected short format — 3 bytes wire size")
|
|
func endCallDisconnectedShortFormat() throws {
|
|
let packet = PacketSignalPeer(src: "ignored", dst: "ignored", sharedPublic: "ignored",
|
|
signalType: .endCallBecausePeerDisconnected, roomId: "ignored")
|
|
let data = PacketRegistry.encode(packet)
|
|
#expect(data.count == 3)
|
|
|
|
let decoded = try decode(packet)
|
|
#expect(decoded.signalType == .endCallBecausePeerDisconnected)
|
|
}
|
|
|
|
private func decode(_ packet: PacketSignalPeer) throws -> PacketSignalPeer {
|
|
let data = PacketRegistry.encode(packet)
|
|
guard let result = PacketRegistry.decode(from: data),
|
|
let decoded = result.packet as? PacketSignalPeer
|
|
else { throw TestError("Failed to decode PacketSignalPeer") }
|
|
#expect(result.packetId == 0x1A)
|
|
return decoded
|
|
}
|
|
}
|
|
|
|
// MARK: - Enum Parity Tests
|
|
|
|
struct CallPushEnumParityTests {
|
|
|
|
@Test("SignalType enum values match server",
|
|
arguments: [
|
|
(SignalType.call, 0), (SignalType.keyExchange, 1), (SignalType.activeCall, 2),
|
|
(SignalType.endCall, 3), (SignalType.createRoom, 4),
|
|
(SignalType.endCallBecausePeerDisconnected, 5), (SignalType.endCallBecauseBusy, 6)
|
|
])
|
|
func signalTypeEnumValues(pair: (SignalType, Int)) {
|
|
#expect(pair.0.rawValue == pair.1)
|
|
}
|
|
|
|
@Test("WebRTCSignalType enum values match server",
|
|
arguments: [(WebRTCSignalType.offer, 0), (WebRTCSignalType.answer, 1),
|
|
(WebRTCSignalType.iceCandidate, 2)])
|
|
func webRTCSignalTypeValues(pair: (WebRTCSignalType, Int)) {
|
|
#expect(pair.0.rawValue == pair.1)
|
|
}
|
|
|
|
@Test("PushTokenType enum values match server")
|
|
func pushTokenTypeValues() {
|
|
#expect(PushTokenType.fcm.rawValue == 0)
|
|
#expect(PushTokenType.voipApns.rawValue == 1)
|
|
}
|
|
}
|
|
|
|
// MARK: - Wire Format Byte-Level Tests
|
|
|
|
struct CallPushWireFormatTests {
|
|
|
|
@Test("PushNotification byte layout: token→action→tokenType→deviceId")
|
|
func pushNotificationByteLayout() {
|
|
var packet = PacketPushNotification()
|
|
packet.notificationsToken = "A"
|
|
packet.action = .unsubscribe
|
|
packet.tokenType = .fcm
|
|
packet.deviceId = "B"
|
|
|
|
let data = PacketRegistry.encode(packet)
|
|
#expect(data.count == 16)
|
|
|
|
// packetId = 0x0010
|
|
#expect(data[0] == 0x00); #expect(data[1] == 0x10)
|
|
// token "A": length=1, 'A'=0x0041
|
|
#expect(data[2] == 0x00); #expect(data[3] == 0x00)
|
|
#expect(data[4] == 0x00); #expect(data[5] == 0x01)
|
|
#expect(data[6] == 0x00); #expect(data[7] == 0x41)
|
|
// action = 1 (unsubscribe)
|
|
#expect(data[8] == 0x01)
|
|
// tokenType = 0 (fcm)
|
|
#expect(data[9] == 0x00)
|
|
// deviceId "B": length=1, 'B'=0x0042
|
|
#expect(data[10] == 0x00); #expect(data[11] == 0x00)
|
|
#expect(data[12] == 0x00); #expect(data[13] == 0x01)
|
|
#expect(data[14] == 0x00); #expect(data[15] == 0x42)
|
|
}
|
|
|
|
@Test("SignalPeer call byte layout: signalType→src→dst")
|
|
func signalPeerCallByteLayout() {
|
|
let packet = PacketSignalPeer(src: "S", dst: "D", sharedPublic: "",
|
|
signalType: .call, roomId: "")
|
|
let data = PacketRegistry.encode(packet)
|
|
#expect(data.count == 15)
|
|
|
|
// packetId = 0x001A
|
|
#expect(data[0] == 0x00); #expect(data[1] == 0x1A)
|
|
// signalType = 0 (call)
|
|
#expect(data[2] == 0x00)
|
|
// src "S": length=1, 'S'=0x0053
|
|
#expect(data[3] == 0x00); #expect(data[4] == 0x00)
|
|
#expect(data[5] == 0x00); #expect(data[6] == 0x01)
|
|
#expect(data[7] == 0x00); #expect(data[8] == 0x53)
|
|
// dst "D": length=1, 'D'=0x0044
|
|
#expect(data[9] == 0x00); #expect(data[10] == 0x00)
|
|
#expect(data[11] == 0x00); #expect(data[12] == 0x01)
|
|
#expect(data[13] == 0x00); #expect(data[14] == 0x44)
|
|
}
|
|
}
|
|
|
|
// MARK: - Helpers
|
|
|
|
private struct TestError: Error, CustomStringConvertible {
|
|
let description: String
|
|
init(_ message: String) { self.description = message }
|
|
}
|