/
/
1"""Test Tidal Playlist Manager."""
2
3from unittest.mock import Mock, patch
4
5import pytest
6
7from music_assistant.providers.tidal.playlist import TidalPlaylistManager
8
9
10@pytest.fixture
11def playlist_manager(provider_mock: Mock) -> TidalPlaylistManager:
12 """Return a TidalPlaylistManager instance."""
13 return TidalPlaylistManager(provider_mock)
14
15
16@patch("music_assistant.providers.tidal.playlist.parse_playlist")
17async def test_create_playlist(
18 mock_parse_playlist: Mock, playlist_manager: TidalPlaylistManager, provider_mock: Mock
19) -> None:
20 """Test create_playlist."""
21 provider_mock.api.post.return_value = {"uuid": "1", "title": "Test Playlist"}
22 mock_parse_playlist.return_value = Mock(item_id="1")
23
24 playlist = await playlist_manager.create("Test Playlist")
25
26 assert playlist.item_id == "1"
27 provider_mock.api.post.assert_called_with(
28 "users/12345/playlists",
29 data={"title": "Test Playlist", "description": ""},
30 as_form=True,
31 )
32 mock_parse_playlist.assert_called_once()
33
34
35async def test_add_playlist_tracks(
36 playlist_manager: TidalPlaylistManager, provider_mock: Mock
37) -> None:
38 """Test add_playlist_tracks."""
39 # Mock get response with ETag
40 provider_mock.api.get_with_etag.return_value = ({"numberOfTracks": 5}, "etag_123")
41
42 await playlist_manager.add_tracks("1", ["track_1", "track_2"])
43
44 provider_mock.api.get_with_etag.assert_called_with("playlists/1")
45 provider_mock.api.post.assert_called_with(
46 "playlists/1/items",
47 data={
48 "onArtifactNotFound": "SKIP",
49 "trackIds": "track_1,track_2",
50 "toIndex": 5,
51 "onDupes": "SKIP",
52 },
53 as_form=True,
54 headers={"If-None-Match": "etag_123"},
55 )
56
57
58async def test_remove_playlist_tracks(
59 playlist_manager: TidalPlaylistManager, provider_mock: Mock
60) -> None:
61 """Test remove_playlist_tracks."""
62 # Mock get response with ETag
63 provider_mock.api.get_with_etag.return_value = ({}, "etag_123")
64
65 # Positions are 1-based in MA, converted to 0-based for Tidal
66 await playlist_manager.remove_tracks("1", (1, 3))
67
68 provider_mock.api.get_with_etag.assert_called_with("playlists/1")
69 provider_mock.api.delete.assert_called_with(
70 "playlists/1/items/0,2",
71 headers={"If-None-Match": "etag_123"},
72 )
73