Files
ios/MusicBridgeTests/SystemPlayerTests.swift
T

55 lines
3.4 KiB
Swift
Raw Normal View History

import XCTest
@testable import MusicBridge
@MainActor
final class SystemPlayerTests: XCTestCase {
private func state(_ changes: [String: Any] = [:]) throws -> MediaState {
let url = try XCTUnwrap(Bundle(for: Self.self).url(forResource: "state-v1", withExtension: "json"))
var json = try XCTUnwrap(JSONSerialization.jsonObject(with: Data(contentsOf: url)) as? [String: Any])
changes.forEach { json[$0.key] = $0.value }
return try JSONDecoder().decode(MediaState.self, from: JSONSerialization.data(withJSONObject: json))
}
func testSeekConvertsRelativePositionAndClampsToAllowedRange() throws {
let state = try state(["startSeconds": 100, "endSeconds": 300, "minSeekSeconds": 110, "maxSeekSeconds": 280])
XCTAssertEqual(try SystemPlayerTransport.command(.seek, value: 30, state: state).value, 130)
XCTAssertEqual(try SystemPlayerTransport.command(.seek, value: -50, state: state).value, 110)
XCTAssertEqual(try SystemPlayerTransport.command(.seek, value: 500, state: state).value, 280)
XCTAssertThrowsError(try SystemPlayerTransport.command(.seek, value: .nan, state: state))
}
func testVolumeBoundsAndUnsupportedPlayback() throws {
let state = try state()
XCTAssertEqual(try SystemPlayerTransport.command(.volume, value: 2, state: state).value, 1)
XCTAssertEqual(try SystemPlayerTransport.command(.volume, value: -1, state: state).value, 0)
XCTAssertThrowsError(try SystemPlayerTransport.command(.volume, value: .infinity, state: state))
XCTAssertThrowsError(try SystemPlayerTransport.command(.play, value: nil, state: state))
XCTAssertThrowsError(try SystemPlayerTransport.command(.next, value: nil, state: self.state(["hasSession": false])))
}
func testRemoteSnapshotContainsOnlyPublicPlaybackMetadata() throws {
guard #available(iOS 27.0, *) else { throw XCTSkip("Requires NowPlaying") }
let snapshot = SystemPlayerAttributes(id: "session", state: try state(["positionSeconds": 130, "startSeconds": 100, "endSeconds": 300]))
XCTAssertEqual(snapshot.position, 30)
XCTAssertEqual(snapshot.duration, 200)
let json = try XCTUnwrap(JSONSerialization.jsonObject(with: JSONEncoder().encode(snapshot)) as? [String: Any])
XCTAssertEqual(Set(json.keys), Set(["id", "title", "artist", "source", "playing", "rate", "position", "duration", "timestamp", "capabilities", "volume", "hasSession"]))
}
func testRevokedSessionDoesNotSendCommandAndNextIsSentOnce() async throws {
let url = try XCTUnwrap(Bundle(for: Self.self).url(forResource: "tls-fixture", withExtension: "json"))
let fixtures = try JSONDecoder().decode([String: [String: String]].self, from: Data(contentsOf: url))
let f = try XCTUnwrap(fixtures["valid"])
let client = BridgeClient(try Connection(endpoint: XCTUnwrap(f["endpoint"]), fingerprint: XCTUnwrap(f["fingerprint"]), token: "live-system-next"))
defer { client.close() }
do {
_ = try await SystemPlayerTransport.execute(.next, client: client) { throw BridgeError.unauthorized }
XCTFail("Revoked session must be rejected")
} catch BridgeError.unauthorized { }
let unchanged = try await client.state()
XCTAssertEqual(unchanged.title, "Track 0")
let updated = try await SystemPlayerTransport.execute(.next, client: client)
XCTAssertEqual(updated.title, "Track 1")
}
}