/
/
/
1"""Test we can parse Tidal models into Music Assistant models."""
2
3import json
4import pathlib
5from typing import TYPE_CHECKING
6from unittest.mock import Mock
7
8import pytest
9
10from music_assistant.providers.tidal.parsers import (
11 parse_album,
12 parse_artist,
13 parse_playlist,
14 parse_track,
15)
16
17if TYPE_CHECKING:
18 from syrupy.assertion import SnapshotAssertion
19
20FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures"
21ARTIST_FIXTURES = list(FIXTURES_DIR.glob("artists/*.json"))
22ALBUM_FIXTURES = list(FIXTURES_DIR.glob("albums/*.json"))
23TRACK_FIXTURES = list(FIXTURES_DIR.glob("tracks/*.json"))
24PLAYLIST_FIXTURES = list(FIXTURES_DIR.glob("playlists/*.json"))
25
26
27@pytest.mark.parametrize("example", ARTIST_FIXTURES, ids=lambda val: str(val.stem))
28def test_parse_artist(
29 example: pathlib.Path, provider_mock: Mock, snapshot: SnapshotAssertion
30) -> None:
31 """Test we can parse artists."""
32 with open(example, encoding="utf-8") as f:
33 data = json.load(f)
34 parsed = parse_artist(provider_mock, data).to_dict()
35 assert snapshot == parsed
36
37
38@pytest.mark.parametrize("example", ALBUM_FIXTURES, ids=lambda val: str(val.stem))
39def test_parse_album(
40 example: pathlib.Path, provider_mock: Mock, snapshot: SnapshotAssertion
41) -> None:
42 """Test we can parse albums."""
43 with open(example, encoding="utf-8") as f:
44 data = json.load(f)
45 parsed = parse_album(provider_mock, data).to_dict()
46 assert snapshot == parsed
47
48
49@pytest.mark.parametrize("example", TRACK_FIXTURES, ids=lambda val: str(val.stem))
50def test_parse_track(
51 example: pathlib.Path, provider_mock: Mock, snapshot: SnapshotAssertion
52) -> None:
53 """Test we can parse tracks."""
54 with open(example, encoding="utf-8") as f:
55 data = json.load(f)
56 parsed = parse_track(provider_mock, data).to_dict()
57 assert snapshot == parsed
58
59
60@pytest.mark.parametrize("example", PLAYLIST_FIXTURES, ids=lambda val: str(val.stem))
61def test_parse_playlist(
62 example: pathlib.Path, provider_mock: Mock, snapshot: SnapshotAssertion
63) -> None:
64 """Test we can parse playlists."""
65 with open(example, encoding="utf-8") as f:
66 data = json.load(f)
67
68 is_mix = "mix" in example.name
69 parsed = parse_playlist(provider_mock, data, is_mix=is_mix).to_dict()
70 assert snapshot == parsed
71
72
73def test_parse_track_partial_album(provider_mock: Mock) -> None:
74 """Test track parsing tolerates partial album objects."""
75 track_obj = {
76 "id": 123,
77 "title": "Test Track",
78 "duration": 100,
79 "artists": [{"id": 1, "name": "Test Artist", "picture": None}],
80 "album": {"id": 456}, # No title or cover
81 }
82
83 track = parse_track(provider_mock, track_obj)
84
85 assert track.album is not None
86 assert track.album.item_id == "456"
87 assert track.album.name == ""
88
89 # An album without an id is useless: no mapping should be created
90 track_obj["album"] = {"title": "Test Album"}
91 track = parse_track(provider_mock, track_obj)
92 assert track.album is None
93
94
95def test_parse_track_skips_artist_with_null_name(provider_mock: Mock) -> None:
96 """Test a malformed artist does not prevent parsing the containing track."""
97 with open(TRACK_FIXTURES[0], encoding="utf-8") as f:
98 data = json.load(f)
99 data["item"]["artists"][0]["name"] = None
100
101 track = parse_track(provider_mock, data)
102
103 assert track.artists == []
104 provider_mock.logger.warning.assert_called_once()
105