/
/
/
1"""Tests for ``provider.resources._uri.parse_resource_uri``."""
2
3from __future__ import annotations
4
5import pytest
6
7from music_assistant.providers.fastmcp_server.resources._uri import ResourceURI, parse_resource_uri
8
9
10@pytest.mark.parametrize(
11 ("uri", "expected"),
12 [
13 ("library://artist/123", ResourceURI("library", "artist", "123")),
14 ("library://album/abc-DEF_42", ResourceURI("library", "album", "abc-DEF_42")),
15 ("library://track/track%3A1", ResourceURI("library", "track", "track%3A1")),
16 ("library://playlist/p1", ResourceURI("library", "playlist", "p1")),
17 ("library://radio/r:1", ResourceURI("library", "radio", "r:1")),
18 ("library://podcast/p1", ResourceURI("library", "podcast", "p1")),
19 ("library://audiobook/a1", ResourceURI("library", "audiobook", "a1")),
20 ("player://kitchen", ResourceURI("player", None, "kitchen")),
21 ("player://livingroom_sonos", ResourceURI("player", None, "livingroom_sonos")),
22 ("queue://q1", ResourceURI("queue", None, "q1")),
23 ],
24)
25def test_parse_valid(uri: str, expected: ResourceURI) -> None:
26 """Valid URIs round-trip into ResourceURI."""
27 assert parse_resource_uri(uri) == expected
28
29
30@pytest.mark.parametrize(
31 "uri",
32 [
33 "",
34 "noscheme",
35 "ftp://library/x",
36 "library://",
37 "library:///",
38 "library://artist/",
39 "library://artist/../etc/passwd",
40 "library://artist/has spaces",
41 "library://unknownkind/x",
42 "player://",
43 "queue://",
44 ],
45)
46def test_parse_invalid(uri: str) -> None:
47 """Invalid URIs raise ``ValueError``."""
48 with pytest.raises(ValueError, match=r".+"):
49 parse_resource_uri(uri)
50
51
52def test_path_traversal_rejected_in_id() -> None:
53 """Two-dot sequences anywhere in the body are rejected as a defence-in-depth measure."""
54 with pytest.raises(ValueError, match=r".+"):
55 parse_resource_uri("library://artist/..foo")
56