You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.5 KiB
148 lines
5.5 KiB
"""Tests for the DLNAClient SOAP and DIDL-Lite parsers.""" |
|
|
|
from r36s_dlna_browser.dlna.client import _extract_browse_result, _parse_didl |
|
from r36s_dlna_browser.dlna.models import ItemType |
|
|
|
|
|
_SAMPLE_DIDL = """\ |
|
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" |
|
xmlns:dc="http://purl.org/dc/elements/1.1/" |
|
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"> |
|
<container id="1" parentID="0" childCount="3"> |
|
<dc:title>Music</dc:title> |
|
<upnp:class>object.container.storageFolder</upnp:class> |
|
</container> |
|
<item id="100" parentID="1"> |
|
<dc:title>Song.mp3</dc:title> |
|
<upnp:class>object.item.audioItem.musicTrack</upnp:class> |
|
<upnp:albumArtURI>http://srv/art.jpg</upnp:albumArtURI> |
|
<res protocolInfo="http-get:*:audio/mpeg:*" size="4000000" duration="0:03:21">http://srv/song.mp3</res> |
|
</item> |
|
<item id="200" parentID="1"> |
|
<dc:title>Video.mkv</dc:title> |
|
<upnp:class>object.item.videoItem</upnp:class> |
|
<res protocolInfo="http-get:*:video/x-matroska:*">http://srv/video.mkv</res> |
|
</item> |
|
</DIDL-Lite> |
|
""" |
|
|
|
|
|
class TestParseDIDL: |
|
def test_parses_container(self): |
|
items = _parse_didl(_SAMPLE_DIDL, "http://srv") |
|
containers = [i for i in items if i.is_container] |
|
assert len(containers) == 1 |
|
assert containers[0].title == "Music" |
|
assert containers[0].child_count == 3 |
|
|
|
def test_parses_audio_item(self): |
|
items = _parse_didl(_SAMPLE_DIDL, "http://srv") |
|
audio = [i for i in items if i.item_type == ItemType.AUDIO] |
|
assert len(audio) == 1 |
|
assert audio[0].title == "Song.mp3" |
|
assert audio[0].resource_url == "http://srv/song.mp3" |
|
assert audio[0].mime_type == "audio/mpeg" |
|
assert audio[0].size == 4000000 |
|
assert audio[0].duration == "0:03:21" |
|
assert audio[0].album_art_url == "http://srv/art.jpg" |
|
|
|
def test_parses_video_item(self): |
|
items = _parse_didl(_SAMPLE_DIDL, "http://srv") |
|
video = [i for i in items if i.item_type == ItemType.VIDEO] |
|
assert len(video) == 1 |
|
assert video[0].title == "Video.mkv" |
|
assert "video/x-matroska" in video[0].mime_type |
|
|
|
def test_total_count(self): |
|
items = _parse_didl(_SAMPLE_DIDL, "http://srv") |
|
assert len(items) == 3 |
|
|
|
def test_empty_didl(self): |
|
empty = '<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"></DIDL-Lite>' |
|
assert _parse_didl(empty, "http://srv") == [] |
|
|
|
def test_malformed_xml(self): |
|
assert _parse_didl("<<<not xml>>>", "http://srv") == [] |
|
|
|
def test_relative_url_resolution(self): |
|
didl = """\ |
|
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" |
|
xmlns:dc="http://purl.org/dc/elements/1.1/" |
|
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"> |
|
<item id="300" parentID="1"> |
|
<dc:title>Relative</dc:title> |
|
<upnp:class>object.item.audioItem</upnp:class> |
|
<res protocolInfo="http-get:*:audio/flac:*">media/track.flac</res> |
|
</item> |
|
</DIDL-Lite> |
|
""" |
|
items = _parse_didl(didl, "http://myserver:8200") |
|
assert items[0].resource_url == "http://myserver:8200/media/track.flac" |
|
|
|
def test_prefers_video_resource_over_subtitle_resource(self): |
|
didl = """\ |
|
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" |
|
xmlns:dc="http://purl.org/dc/elements/1.1/" |
|
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"> |
|
<item id="400" parentID="1"> |
|
<dc:title>Movie</dc:title> |
|
<upnp:class>object.item.videoItem</upnp:class> |
|
<res protocolInfo="http-get:*:text/vtt:*">http://srv/movie.vtt</res> |
|
<res protocolInfo="http-get:*:video/x-matroska:*" size="999">http://srv/movie.mkv</res> |
|
</item> |
|
</DIDL-Lite> |
|
""" |
|
items = _parse_didl(didl, "http://srv") |
|
assert items[0].resource_url == "http://srv/movie.mkv" |
|
assert items[0].mime_type == "video/x-matroska" |
|
|
|
|
|
class TestExtractBrowseResult: |
|
def test_extracts_unnamespaced_result(self): |
|
soap = """\ |
|
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> |
|
<s:Body> |
|
<u:BrowseResponse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"> |
|
<Result><DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><container id="1" parentID="0" /></DIDL-Lite></Result> |
|
</u:BrowseResponse> |
|
</s:Body> |
|
</s:Envelope> |
|
""" |
|
result = _extract_browse_result(soap) |
|
assert result is not None |
|
assert "DIDL-Lite" in result |
|
assert 'container id="1"' in result |
|
|
|
def test_extracts_namespaced_result(self): |
|
soap = """\ |
|
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"> |
|
<s:Body> |
|
<u:BrowseResponse> |
|
<u:Result><DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"></DIDL-Lite></u:Result> |
|
</u:BrowseResponse> |
|
</s:Body> |
|
</s:Envelope> |
|
""" |
|
assert _extract_browse_result(soap) is not None |
|
|
|
def test_extracts_embedded_xml_result(self): |
|
soap = """\ |
|
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> |
|
<s:Body> |
|
<BrowseResponse> |
|
<Result> |
|
<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"> |
|
<container id="1" parentID="0" /> |
|
</DIDL-Lite> |
|
</Result> |
|
</BrowseResponse> |
|
</s:Body> |
|
</s:Envelope> |
|
""" |
|
result = _extract_browse_result(soap) |
|
assert result is not None |
|
assert "DIDL-Lite" in result |
|
|
|
def test_returns_none_when_missing(self): |
|
soap = "<Envelope><Body><BrowseResponse /></Body></Envelope>" |
|
assert _extract_browse_result(soap) is None
|
|
|