Files
mobile-ios/RosettaTests/PushNotificationPacketTests.swift

166 lines
5.3 KiB
Swift

import Testing
@testable import Rosetta
/// Verifies PacketPushNotification wire format matches Server/Android:
/// writeInt16(packetId=0x10)
/// writeString(notificationToken)
/// writeInt8(action)
/// writeInt8(tokenType)
/// writeString(deviceId)
struct PushNotificationPacketTests {
// MARK: - Enum Value Parity
@Test("PushNotificationAction.subscribe == 0 (server: SUBSCRIBE)")
func subscribeActionValue() {
#expect(PushNotificationAction.subscribe.rawValue == 0)
}
@Test("PushNotificationAction.unsubscribe == 1 (server: UNSUBSCRIBE)")
func unsubscribeActionValue() {
#expect(PushNotificationAction.unsubscribe.rawValue == 1)
}
@Test("PushTokenType.fcm == 0")
func fcmTokenTypeValue() {
#expect(PushTokenType.fcm.rawValue == 0)
}
@Test("PushTokenType.voipApns == 1")
func voipTokenTypeValue() {
#expect(PushTokenType.voipApns.rawValue == 1)
}
// MARK: - Round Trip (encode decode)
@Test("Subscribe round-trip preserves all fields")
func subscribeRoundTrip() throws {
var packet = PacketPushNotification()
packet.notificationsToken = "test-fcm-token-abc123"
packet.action = .subscribe
packet.tokenType = .fcm
packet.deviceId = "ios-device-1"
let decoded = try decodePushNotification(packet)
#expect(decoded.notificationsToken == "test-fcm-token-abc123")
#expect(decoded.action == .subscribe)
#expect(decoded.tokenType == .fcm)
#expect(decoded.deviceId == "ios-device-1")
}
@Test("Unsubscribe round-trip preserves all fields")
func unsubscribeRoundTrip() throws {
var packet = PacketPushNotification()
packet.notificationsToken = "test-token-deadbeef"
packet.action = .unsubscribe
packet.tokenType = .voipApns
packet.deviceId = "ios-device-2"
let decoded = try decodePushNotification(packet)
#expect(decoded.notificationsToken == "test-token-deadbeef")
#expect(decoded.action == .unsubscribe)
#expect(decoded.tokenType == .voipApns)
#expect(decoded.deviceId == "ios-device-2")
}
@Test("Empty token round-trip")
func emptyFieldsRoundTrip() throws {
var packet = PacketPushNotification()
packet.notificationsToken = ""
packet.action = .subscribe
packet.tokenType = .fcm
packet.deviceId = ""
let decoded = try decodePushNotification(packet)
#expect(decoded.notificationsToken == "")
#expect(decoded.tokenType == .fcm)
#expect(decoded.deviceId == "")
}
// MARK: - Wire Format Byte Verification
@Test("Packet ID is 0x10 in encoded data")
func packetIdInEncodedData() {
#expect(PacketPushNotification.packetId == 0x10)
let packet = PacketPushNotification()
let data = PacketRegistry.encode(packet)
// First 2 bytes = packetId in big-endian: 0x00 0x10
#expect(data.count >= 2)
#expect(data[0] == 0x00)
#expect(data[1] == 0x10)
}
@Test("Wire format field order matches server: token → action → tokenType → deviceId")
func wireFormatFieldOrder() throws {
// Use known short values so we can verify byte positions.
var packet = PacketPushNotification()
packet.notificationsToken = "T" // 1 UTF-16 code unit
packet.action = .subscribe // 0
packet.tokenType = .fcm // 0
packet.deviceId = "D" // 1 UTF-16 code unit
let data = PacketRegistry.encode(packet)
// Expected layout:
// [0-1] packetId = 0x0010 (2 bytes)
// [2-5] string length = 1 (UInt32 big-endian) for "T"
// [6-7] 'T' = 0x0054 (UInt16 big-endian)
// [8] action = 0 (subscribe)
// [9] tokenType = 0 (fcm)
// [10-13] string length = 1 for "D"
// [14-15] 'D' = 0x0044
#expect(data.count == 16)
// packetId
#expect(data[0] == 0x00)
#expect(data[1] == 0x10)
// token string length = 1
#expect(data[2] == 0x00)
#expect(data[3] == 0x00)
#expect(data[4] == 0x00)
#expect(data[5] == 0x01)
// 'T' in UTF-16 BE
#expect(data[6] == 0x00)
#expect(data[7] == 0x54)
// action = 0 (subscribe)
#expect(data[8] == 0x00)
// tokenType = 0 (fcm)
#expect(data[9] == 0x00)
// deviceId string length = 1
#expect(data[10] == 0x00)
#expect(data[11] == 0x00)
#expect(data[12] == 0x00)
#expect(data[13] == 0x01)
// 'D' in UTF-16 BE
#expect(data[14] == 0x00)
#expect(data[15] == 0x44)
}
// MARK: - Helper
private func decodePushNotification(
_ packet: PacketPushNotification
) throws -> PacketPushNotification {
let encoded = PacketRegistry.encode(packet)
guard let decoded = PacketRegistry.decode(from: encoded),
let decodedPacket = decoded.packet as? PacketPushNotification
else {
throw NSError(
domain: "PushNotificationPacketTests", code: 1,
userInfo: [NSLocalizedDescriptionKey: "Failed to decode PacketPushNotification"]
)
}
#expect(decoded.packetId == 0x10)
return decodedPacket
}
}