/
/
1"""Tests for MilkDrop visualizer target resolution."""
2
3from __future__ import annotations
4
5from unittest.mock import Mock
6
7from music_assistant_models.enums import PlaybackState
8
9from music_assistant.providers.milkdrop_visualizer.relay import MilkdropRelay
10from music_assistant.providers.sendspin.player import SendspinBasePlayer
11
12
13def _relay(players: list[Mock]) -> MilkdropRelay:
14 """Return a relay whose mass exposes the given players."""
15 provider = Mock()
16 provider.mass.players = players
17 provider.logger.getChild.return_value = Mock()
18 return MilkdropRelay(provider)
19
20
21def _player(
22 player_id: str,
23 *,
24 underlying: str | None = None,
25 playing: bool = False,
26) -> Mock:
27 """Build a SendspinBasePlayer-shaped mock the resolver will accept."""
28 player = Mock(spec=SendspinBasePlayer)
29 player.player_id = player_id
30 player.underlying_player_id = underlying
31 player.display_name = player_id
32 player.api = Mock()
33 player.playback_state = PlaybackState.PLAYING if playing else PlaybackState.IDLE
34 return player
35
36
37def test_resolves_exact_player_id() -> None:
38 """A query equal to a player id resolves to that player."""
39 target = _player("20:F8:3B:09:00:F6")
40 relay = _relay([_player("aa:bb:cc:dd:ee:ff"), target])
41 assert relay._resolve_target("20:F8:3B:09:00:F6") is target
42
43
44def test_resolves_universal_wrapper_id_by_suffix() -> None:
45 """A universal player id ('up' + normalized MAC) matches the Sendspin device it wraps."""
46 target = _player("20:F8:3B:09:00:F6")
47 relay = _relay([target])
48 assert relay._resolve_target("up20f83b0900f6") is target
49
50
51def test_unmatched_player_returns_none_rather_than_guessing() -> None:
52 """A named player with no Sendspin group resolves to None instead of an arbitrary tap."""
53 relay = _relay([_player("20:F8:3B:09:00:F6", playing=True)])
54 assert relay._resolve_target("some-chromecast-id") is None
55
56
57def test_no_query_auto_picks_the_playing_player() -> None:
58 """With no query, the currently-playing Sendspin player wins over idle ones."""
59 idle = _player("aa:bb:cc:dd:ee:ff")
60 playing = _player("20:F8:3B:09:00:F6", playing=True)
61 relay = _relay([idle, playing])
62 assert relay._resolve_target(None) is playing
63
64
65def test_no_players_returns_none() -> None:
66 """With no Sendspin players at all, resolution yields None."""
67 relay = _relay([])
68 assert relay._resolve_target(None) is None
69