Unit tests und nudging screen

This commit is contained in:
2026-04-20 11:10:53 +02:00
parent e1aebdb916
commit 3858500a45
8 changed files with 1223 additions and 0 deletions
@@ -0,0 +1,120 @@
import Testing
import Foundation
@testable import Mobile_Music_Assistant
// MARK: - Live Activity Player Selection
@Suite("MAPlayerManager Live Activity Selection")
struct LiveActivitySelectionTests {
/// Build a minimal MAPlayer from JSON for testing.
private func makePlayer(
id: String,
state: String = "playing",
currentItem: String? = nil
) throws -> MAPlayer {
var json = """
{"player_id":"\(id)","name":"Player \(id)","state":"\(state)"}
"""
if let item = currentItem {
json = """
{"player_id":"\(id)","name":"Player \(id)","state":"\(state)","current_item":{"queue_item_id":"qi1","name":"\(item)"}}
"""
}
return try JSONDecoder().decode(MAPlayer.self, from: Data(json.utf8))
}
// The selection logic is internal to MAPlayerManager; we test it via
// a whitebox helper that replicates the exact algorithm.
private func selectBestPlayer(
from players: [MAPlayer],
queues: [String: MAPlayerQueue]
) -> MAPlayer? {
players
.filter { $0.state == .playing }
.first { p in p.currentItem != nil || queues[p.playerId]?.currentItem != nil }
?? players.first { $0.state == .playing }
}
@Test("Selects the playing player with a known currentItem")
func selectsPlayingWithItem() throws {
let playing = try makePlayer(id: "1", state: "playing", currentItem: "Song A")
let idle = try makePlayer(id: "2", state: "idle")
let selected = selectBestPlayer(from: [idle, playing], queues: [:])
#expect(selected?.playerId == "1")
}
@Test("Falls back to any playing player when no current item is set")
func fallsBackToAnyPlayingPlayer() throws {
let playing = try makePlayer(id: "1", state: "playing")
let idle = try makePlayer(id: "2", state: "idle")
let selected = selectBestPlayer(from: [idle, playing], queues: [:])
#expect(selected?.playerId == "1")
}
@Test("Returns nil when no player is playing")
func returnsNilWhenNobodyPlaying() throws {
let p1 = try makePlayer(id: "1", state: "idle")
let p2 = try makePlayer(id: "2", state: "paused")
let selected = selectBestPlayer(from: [p1, p2], queues: [:])
#expect(selected == nil)
}
@Test("Prefers player whose queue has a currentItem")
func prefersPlayerWithQueueItem() throws {
let p1 = try makePlayer(id: "1", state: "playing") // no direct item
let p2 = try makePlayer(id: "2", state: "playing") // no direct item
let queue2: MAPlayerQueue = try {
let json = """
{"queue_id":"q2","current_item":{"queue_item_id":"qi2","name":"Track"}}
"""
return try JSONDecoder().decode(MAPlayerQueue.self, from: Data(json.utf8))
}()
// p1 has no item in players or queues; p2 has item in queue
let selected = selectBestPlayer(from: [p1, p2], queues: ["2": queue2])
#expect(selected?.playerId == "2")
}
@Test("Returns nil with empty player list")
func emptyPlayerList() {
let selected = selectBestPlayer(from: [], queues: [:])
#expect(selected == nil)
}
}
// MARK: - ResizeAndEncode
@Suite("MAPlayerManager resizeAndEncode")
struct ResizeAndEncodeTests {
@Test("Encodes UIImage to JPEG data under 4 KB")
func encodedDataIsBelowActivityKitLimit() {
let size = CGSize(width: 400, height: 400)
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { ctx in
UIColor.systemBlue.setFill()
ctx.fill(CGRect(origin: .zero, size: size))
}
let data = MAPlayerManager.testResizeAndEncode(image)
#expect(data != nil)
// ActivityKit limit is 4 KB; we target <1 KB for the image
#expect((data?.count ?? Int.max) < 4096)
}
@Test("Returns valid JPEG data")
func returnsValidJpeg() {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 100, height: 100))
let image = renderer.image { ctx in
UIColor.red.setFill()
ctx.fill(CGRect(origin: .zero, size: CGSize(width: 100, height: 100)))
}
guard let data = MAPlayerManager.testResizeAndEncode(image) else {
Issue.record("resizeAndEncode returned nil")
return
}
// JPEG magic bytes: FF D8
#expect(data.prefix(2) == Data([0xFF, 0xD8]))
}
}