import Foundation
import Testing
@testable import IrdP2PSignaling
import IrdP2PCrypto
@Suite struct FrameCodecTests {
@Test func clientFramesEncodeInDocumentedOrder() {
#expect(ClientFrame.join(room: testRoom, peer: testPeer).encoded == #"{"t":"join","room":"\#(testRoom.string)","peer":"\#(testPeer.hex)"}"#)
#expect(ClientFrame.signal(to: otherPeer, payload: .object(["v": .int(1)])).encoded == #"{"t":"signal","to":"\#(otherPeer.hex)","payload":{"v":1}}"#)
#expect(ClientFrame.leave.encoded == #"{"t":"leave"}"#)
#expect(ClientFrame.ping.encoded == #"{"t":"ping"}"#)
}
@Test func serverFramesDecode() throws {
#expect(try ServerFrame.decode(#"{"t":"peers","peers":["\#(testPeer.hex)","\#(otherPeer.hex)"]}"#) == .peers([testPeer, otherPeer]))
#expect(try ServerFrame.decode(#"{"t":"peers"}"#) == .peers([]))
#expect(try ServerFrame.decode(#"{"t":"peer-joined","peer":"\#(testPeer.hex)"}"#) == .peerJoined(testPeer))
#expect(try ServerFrame.decode(#"{"t":"peer-left","peer":"\#(testPeer.hex)"}"#) == .peerLeft(testPeer))
#expect(try ServerFrame.decode(#"{"t":"signal","from":"\#(testPeer.hex)","payload":{"v":1,"iv":"x","ct":"y"}}"#) == .signal(from: testPeer, payload: .object(["v": .int(1), "iv": .string("x"), "ct": .string("y")])))
#expect(try ServerFrame.decode(#"{"t":"pong"}"#) == .pong)
#expect(try ServerFrame.decode(#"{"t":"error","code":"room-full"}"#) == .error(.roomFull))
#expect(try ServerFrame.decode(#"{"t":"error","code":"brand-new"}"#) == .error(.other("brand-new")))
}
@Test func toleratesUnknownTypesAndKeys() throws {
#expect(try ServerFrame.decode(#"{"t":"weather","sun":true}"#) == .unknown(type: "weather"))
#expect(try ServerFrame.decode(#"{"t":"pong","extra":[1,2]}"#) == .pong)
#expect(try ServerFrame.decode(#"{"t":"peer-left","peer":"\#(testPeer.hex)","since":5}"#) == .peerLeft(testPeer))
}
@Test func rejectsMalformed() {
#expect(throws: ServerFrame.DecodeError.self) { try ServerFrame.decode("not json") }
#expect(throws: ServerFrame.DecodeError.self) { try ServerFrame.decode(#"{"x":1}"#) }
#expect(throws: ServerFrame.DecodeError.self) { try ServerFrame.decode(#"{"t":"peer-joined","peer":"UPPER"}"#) }
#expect(throws: ServerFrame.DecodeError.self) { try ServerFrame.decode(#"{"t":"signal","from":"\#(testPeer.hex)"}"#) }
#expect(throws: ServerFrame.DecodeError.self) { try ServerFrame.decode(#"{"t":"peers","peers":["bad"]}"#) }
}
@Test func errorCodesRoundTrip() {
for raw in ["bad-message", "not-joined", "too-many-rooms", "room-full", "rate-limited", "new-code"] {
#expect(RelayErrorCode(raw).rawValue == raw)
}
#expect(MailboxErrorCode("message_too_large") == .messageTooLarge)
#expect(MailboxErrorCode("token_expired").isAuth)
#expect(MailboxErrorCode("rate_limited").isRetryable)
#expect(!MailboxErrorCode("unknown_app").isRetryable)
}
}