/
/
/
1"""Test the Tidal JSON:API document helper."""
2
3from music_assistant.providers.tidal.jsonapi import JsonApiDocument
4
5
6def test_data_and_data_list() -> None:
7 """Test primary data accessors for single and collection documents."""
8 single = JsonApiDocument({"data": {"id": "1", "type": "tracks"}})
9 assert single.data == {"id": "1", "type": "tracks"}
10 assert single.data_list == []
11
12 collection = JsonApiDocument({"data": [{"id": "1"}, {"id": "2"}]})
13 assert collection.data == {}
14 assert len(collection.data_list) == 2
15
16
17def test_related_resolves_included() -> None:
18 """Test relationship linkages resolve against the included resources."""
19 doc = JsonApiDocument(
20 {
21 "data": {
22 "id": "t1",
23 "type": "tracks",
24 "relationships": {
25 "artists": {"data": [{"id": "a1", "type": "artists"}]},
26 "albums": {"data": {"id": "al1", "type": "albums"}},
27 },
28 },
29 "included": [
30 {"id": "a1", "type": "artists", "attributes": {"name": "Artist One"}},
31 {"id": "al1", "type": "albums", "attributes": {"title": "Album One"}},
32 ],
33 }
34 )
35
36 artists = doc.related(doc.data, "artists")
37 assert [a["attributes"]["name"] for a in artists] == ["Artist One"]
38
39 album = doc.related_one(doc.data, "albums")
40 assert album is not None
41 assert album["attributes"]["title"] == "Album One"
42
43
44def test_related_missing_and_unresolvable() -> None:
45 """Test relationships that are absent or not included resolve to empty."""
46 doc = JsonApiDocument(
47 {
48 "data": {
49 "id": "t1",
50 "type": "tracks",
51 "relationships": {
52 "artists": {"data": [{"id": "missing", "type": "artists"}]},
53 },
54 },
55 "included": [],
56 }
57 )
58 assert doc.related(doc.data, "artists") == []
59 assert doc.related(doc.data, "albums") == []
60 assert doc.related_one(doc.data, "albums") is None
61
62
63def test_next_cursor() -> None:
64 """Test the next cursor is extracted from the links object."""
65 assert JsonApiDocument({"links": {}}).next_cursor is None
66 doc = JsonApiDocument({"links": {"next": "/tracks?countryCode=AT&page[cursor]=abc123&other=1"}})
67 assert doc.next_cursor == "abc123"
68 # A next link without a page[cursor] param is not a usable cursor: guessing
69 # would fire a malformed follow-up request, so the walk must stop cleanly.
70 no_cursor = JsonApiDocument({"links": {"next": "/tracks?countryCode=AT"}})
71 assert no_cursor.next_cursor is None
72
73
74def test_next_cursor_percent_encoded_brackets() -> None:
75 """Test the cursor is extracted when the bracket key is percent-encoded."""
76 # This is the real form Tidal returns: page%5Bcursor%5D=<value>.
77 doc = JsonApiDocument(
78 {"links": {"next": "/x?include=items.profileArt&page%5Bcursor%5D=eyJpZCI6Mzk3fQ"}}
79 )
80 assert doc.next_cursor == "eyJpZCI6Mzk3fQ"
81