import XCTest @testable import CallsKit /// Spec §15.19 on the native side: the core puts each peer's reported /// media on the roster snapshot, and the tiles read it through Call. What /// is held here is the part that can be wrong without a call running — /// the wire shape, and unknown never reading as muted or off. final class PeerMediaTests: XCTestCase { private func state(_ json: String) throws -> RoomState { try JSONDecoder().decode(RoomState.self, from: Data(json.utf8)) } func testARosterCarriesReportedMediaAndLeavesTheRestUnknown() throws { let s = try state( #""" {"phase":"admitted","peer":"me","boot":"b","waiting":[],"peers":[ {"peer":"me","name":"Me","kind":"member","media":{"muted":false,"cameraOff":false}}, {"peer":"bea","name":"Bea","kind":"member","gen":1,"media":{"muted":true,"cameraOff":true}}, {"peer":"old","name":"Old","kind":"guest","gen":1} ]} """#) XCTAssertEqual(Call.peerMedia("bea", in: s), PeerMedia(muted: true, cameraOff: true)) // A client from before §15.19 never reports: the snapshot says // nothing, and nothing is guessed. XCTAssertNil(Call.peerMedia("old", in: s)) XCTAssertNil(Call.peerMedia("nobody", in: s)) XCTAssertNil(Call.peerMedia("bea", in: nil)) } func testAMalformedReportDoesNotCostTheWholeState() throws { // The core only ever forwards two booleans, but a snapshot the app // cannot decode is a call that stops updating, so the shape is pinned. XCTAssertThrowsError( try state( #"{"phase":"admitted","peer":"me","boot":"b","waiting":[],"peers":[{"peer":"x","name":"X","kind":"member","media":{"muted":"yes","cameraOff":false}}]}"# )) } @MainActor func testUnknownIsNeitherMutedNorOff() { let call = Call(playAudio: false) XCTAssertFalse(call.isMuted("anyone")) XCTAssertFalse(call.isCameraOff("anyone")) XCTAssertNil(call.peerMedia("anyone")) } func testTheTileSaysMutedInWordsForVoiceOver() { XCTAssertEqual(tileAccessibilityLabel("Bea", muted: true), "Bea, muted") XCTAssertEqual(tileAccessibilityLabel("Bea", muted: false), "Bea") } }