You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Music/MusicTests/RemoteProtocolTests.swift

132 lines
4.3 KiB

import Foundation
import Testing
@testable import Music
struct RemoteProtocolTests {
private let encoder: JSONEncoder = {
let e = JSONEncoder()
e.outputFormatting = [.sortedKeys]
return e
}()
private let decoder = JSONDecoder()
// MARK: - Helpers
/// Encode then decode a value, returning the decoded copy.
private func roundTrip<T: Codable>(_ value: T) throws -> T {
let data = try encoder.encode(value)
return try decoder.decode(T.self, from: data)
}
// MARK: - RemoteCommand round-trip tests
// Each test encodes a RemoteCommand case to JSON and decodes it back,
// verifying the decoded value equals the original.
@Test func remoteCommandRoundTrip_play() throws {
let cmd = RemoteCommand.play(trackId: 42, queueIds: [42, 43, 44, 45])
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_pause() throws {
let cmd = RemoteCommand.pause
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_resume() throws {
let cmd = RemoteCommand.resume
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_next() throws {
let cmd = RemoteCommand.next
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_previous() throws {
let cmd = RemoteCommand.previous
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_seek() throws {
let cmd = RemoteCommand.seek(position: 123.456)
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_setVolume() throws {
let cmd = RemoteCommand.setVolume(level: 0.75)
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_toggleShuffle() throws {
let cmd = RemoteCommand.toggleShuffle
#expect(try roundTrip(cmd) == cmd)
}
@Test func remoteCommandRoundTrip_refreshDB() throws {
let cmd = RemoteCommand.refreshDB
#expect(try roundTrip(cmd) == cmd)
}
// MARK: - HostEvent round-trip tests
// Each test encodes a HostEvent case to JSON and decodes it back,
// verifying the decoded value equals the original.
@Test func hostEventRoundTrip_playbackState() throws {
let payload = PlaybackStatePayload(
trackId: 7,
isPlaying: true,
currentTime: 42.5,
duration: 210.0,
volume: 0.8,
isShuffled: false
)
let event = HostEvent.playbackState(payload)
#expect(try roundTrip(event) == event)
}
@Test func hostEventRoundTrip_dbReady() throws {
let event = HostEvent.dbReady
#expect(try roundTrip(event) == event)
}
@Test func hostEventRoundTrip_error() throws {
let event = HostEvent.error(message: "Something went wrong")
#expect(try roundTrip(event) == event)
}
// MARK: - HandshakeMessage round-trip test
// Verifies HandshakeMessage survives JSON encoding and decoding.
@Test func handshakeMessageRoundTrip() throws {
let msg = HandshakeMessage(protocolVersion: RemoteProtocolVersion, appVersion: "1.2.3")
#expect(try roundTrip(msg) == msg)
}
// MARK: - Wire format decode tests
// Verify that hand-crafted JSON strings matching the expected wire format
// decode correctly, ensuring the Codable implementation matches the spec.
@Test func wireFormatDecode_playCommand() throws {
let json = """
{"type":"play","payload":{"trackId":42,"queueIds":[42,43,44,45]}}
"""
let decoded = try decoder.decode(RemoteCommand.self, from: Data(json.utf8))
#expect(decoded == .play(trackId: 42, queueIds: [42, 43, 44, 45]))
}
@Test func wireFormatDecode_playbackStateEvent() throws {
let json = """
{"type":"playbackState","payload":{"trackId":7,"isPlaying":true,"currentTime":42.5,"duration":210.0,"volume":0.8,"isShuffled":false}}
"""
let decoded = try decoder.decode(HostEvent.self, from: Data(json.utf8))
let expected = HostEvent.playbackState(PlaybackStatePayload(
trackId: 7,
isPlaying: true,
currentTime: 42.5,
duration: 210.0,
volume: 0.8,
isShuffled: false
))
#expect(decoded == expected)
}
}