/
/
/
1"""Test Tidal Media Manager."""
2
3from typing import Any
4from unittest.mock import AsyncMock, MagicMock, Mock, patch
5
6import pytest
7from music_assistant_models.enums import MediaType
8from music_assistant_models.media_items import ItemMapping
9
10from music_assistant.providers.tidal.media import TidalMediaManager
11
12
13@pytest.fixture
14def provider_mock() -> Mock:
15 """Return a mock provider."""
16 provider = Mock()
17 provider.domain = "tidal"
18 provider.instance_id = "tidal_instance"
19 provider.auth.user_id = "12345"
20 provider.auth.country_code = "US"
21 provider.api = AsyncMock()
22 provider.api.get_data.return_value = {}
23 provider.api.paginate = MagicMock()
24
25 async def async_iter(*_args: Any, **_kwargs: Any) -> Any:
26 for item in provider.api.paginate.return_value:
27 yield item
28
29 provider.api.paginate.side_effect = async_iter
30 provider.api.paginate.return_value = []
31
32 provider.logger = Mock()
33
34 def get_item_mapping(media_type: MediaType, key: str, name: str) -> ItemMapping:
35 return ItemMapping(
36 media_type=media_type,
37 item_id=key,
38 provider=provider.instance_id,
39 name=name,
40 )
41
42 provider.get_item_mapping.side_effect = get_item_mapping
43
44 return provider
45
46
47@pytest.fixture
48def media_manager(provider_mock: Mock) -> TidalMediaManager:
49 """Return a TidalMediaManager instance."""
50 return TidalMediaManager(provider_mock)
51
52
53@patch("music_assistant.providers.tidal.media.parse_artist")
54@patch("music_assistant.providers.tidal.media.parse_album")
55@patch("music_assistant.providers.tidal.media.parse_track")
56@patch("music_assistant.providers.tidal.media.parse_playlist")
57async def test_search(
58 mock_parse_playlist: Mock,
59 mock_parse_track: Mock,
60 mock_parse_album: Mock,
61 mock_parse_artist: Mock,
62 media_manager: TidalMediaManager,
63 provider_mock: Mock,
64) -> None:
65 """Test search."""
66 provider_mock.api.get_data.return_value = {
67 "artists": {"items": [{"id": 1}]},
68 "albums": {"items": [{"id": 1}]},
69 "tracks": {"items": [{"id": 1}]},
70 "playlists": {"items": [{"uuid": "1"}]},
71 }
72
73 mock_parse_artist.return_value = Mock(item_id="1", media_type=MediaType.ARTIST)
74 mock_parse_album.return_value = Mock(item_id="1", media_type=MediaType.ALBUM)
75 mock_parse_track.return_value = Mock(item_id="1", media_type=MediaType.TRACK)
76 mock_parse_playlist.return_value = Mock(item_id="1", media_type=MediaType.PLAYLIST)
77
78 results = await media_manager.search(
79 "query", [MediaType.ARTIST, MediaType.ALBUM, MediaType.TRACK, MediaType.PLAYLIST]
80 )
81
82 assert len(results.artists) == 1
83 assert len(results.albums) == 1
84 assert len(results.tracks) == 1
85 assert len(results.playlists) == 1
86
87 mock_parse_artist.assert_called()
88 mock_parse_album.assert_called()
89 mock_parse_track.assert_called()
90 mock_parse_playlist.assert_called()
91
92 provider_mock.api.get_data.assert_called_with(
93 "search",
94 params={
95 "query": "query",
96 "types": "artists,albums,tracks,playlists",
97 "limit": 5,
98 },
99 )
100
101
102@patch("music_assistant.providers.tidal.media.parse_artist")
103async def test_get_artist(
104 mock_parse_artist: Mock, media_manager: TidalMediaManager, provider_mock: Mock
105) -> None:
106 """Test get_artist."""
107 provider_mock.api.get_data.return_value = {"id": 1, "name": "Test Artist"}
108 mock_parse_artist.return_value = Mock(item_id="1")
109
110 artist = await media_manager.get_artist("1")
111
112 assert artist.item_id == "1"
113 provider_mock.api.get_data.assert_called_with("artists/1")
114 mock_parse_artist.assert_called_once()
115
116
117@patch("music_assistant.providers.tidal.media.parse_album")
118async def test_get_album(
119 mock_parse_album: Mock, media_manager: TidalMediaManager, provider_mock: Mock
120) -> None:
121 """Test get_album."""
122 provider_mock.api.get_data.return_value = {"id": 1, "title": "Test Album"}
123 mock_parse_album.return_value = Mock(item_id="1")
124
125 album = await media_manager.get_album("1")
126
127 assert album.item_id == "1"
128 provider_mock.api.get_data.assert_called_with("albums/1")
129 mock_parse_album.assert_called_once()
130
131
132@patch("music_assistant.providers.tidal.media.parse_track")
133async def test_get_track(
134 mock_parse_track: Mock, media_manager: TidalMediaManager, provider_mock: Mock
135) -> None:
136 """Test get_track."""
137 provider_mock.api.get_data.side_effect = [
138 {"id": 1, "title": "Test Track"}, # Track data
139 {"lyrics": "Test Lyrics"}, # Lyrics data
140 ]
141 mock_parse_track.return_value = Mock(item_id="1")
142
143 track = await media_manager.get_track("1")
144
145 assert track.item_id == "1"
146 assert provider_mock.api.get_data.call_count == 2
147 provider_mock.api.get_data.assert_any_call("tracks/1")
148 provider_mock.api.get_data.assert_any_call("tracks/1/lyrics")
149 mock_parse_track.assert_called_once()
150
151
152@patch("music_assistant.providers.tidal.media.parse_playlist")
153async def test_get_playlist(
154 mock_parse_playlist: Mock, media_manager: TidalMediaManager, provider_mock: Mock
155) -> None:
156 """Test get_playlist."""
157 provider_mock.api.get_data.return_value = {"uuid": "1", "title": "Test Playlist"}
158 mock_parse_playlist.return_value = Mock(item_id="1")
159
160 playlist = await media_manager.get_playlist("1")
161
162 assert playlist.item_id == "1"
163 provider_mock.api.get_data.assert_called_with("playlists/1")
164 mock_parse_playlist.assert_called_once()
165
166
167@patch("music_assistant.providers.tidal.media.parse_track")
168async def test_get_album_tracks(
169 mock_parse_track: Mock, media_manager: TidalMediaManager, provider_mock: Mock
170) -> None:
171 """Test get_album_tracks."""
172 provider_mock.api.get_data.return_value = {"items": [{"id": 1}]}
173 mock_parse_track.return_value = Mock(item_id="1")
174
175 tracks = await media_manager.get_album_tracks("1")
176
177 assert len(tracks) == 1
178 assert tracks[0].item_id == "1"
179 provider_mock.api.get_data.assert_called_with(
180 "albums/1/tracks",
181 params={"limit": 250},
182 )
183
184
185@patch("music_assistant.providers.tidal.media.parse_album")
186async def test_get_artist_albums(
187 mock_parse_album: Mock, media_manager: TidalMediaManager, provider_mock: Mock
188) -> None:
189 """Test get_artist_albums."""
190 provider_mock.api.get_data.return_value = {"items": [{"id": 1}]}
191 mock_parse_album.return_value = Mock(item_id="1")
192
193 albums = await media_manager.get_artist_albums("1")
194
195 assert len(albums) == 1
196 assert albums[0].item_id == "1"
197 provider_mock.api.get_data.assert_called_with(
198 "artists/1/albums",
199 params={"limit": 250},
200 )
201
202
203@patch("music_assistant.providers.tidal.media.parse_track")
204async def test_get_artist_toptracks(
205 mock_parse_track: Mock, media_manager: TidalMediaManager, provider_mock: Mock
206) -> None:
207 """Test get_artist_toptracks."""
208 provider_mock.api.get_data.return_value = {"items": [{"id": 1}]}
209 mock_parse_track.return_value = Mock(item_id="1")
210
211 tracks = await media_manager.get_artist_toptracks("1")
212
213 assert len(tracks) == 1
214 assert tracks[0].item_id == "1"
215 provider_mock.api.get_data.assert_called_with(
216 "artists/1/toptracks",
217 params={"limit": 10, "offset": 0},
218 )
219
220
221@patch("music_assistant.providers.tidal.media.parse_track")
222async def test_get_playlist_tracks(
223 mock_parse_track: Mock, media_manager: TidalMediaManager, provider_mock: Mock
224) -> None:
225 """Test get_playlist_tracks."""
226 provider_mock.api.get_data.return_value = {"items": [{"id": 1}]}
227 mock_parse_track.return_value = Mock(item_id="1")
228
229 tracks = await media_manager.get_playlist_tracks("1")
230
231 assert len(tracks) == 1
232 assert tracks[0].item_id == "1"
233 provider_mock.api.get_data.assert_called_with(
234 "playlists/1/tracks",
235 params={"limit": 200, "offset": 0},
236 )
237