merge jodal master
This commit is contained in:
commit
26ebdda214
2
docs/_themes/nature/static/nature.css_t
vendored
2
docs/_themes/nature/static/nature.css_t
vendored
@ -30,7 +30,7 @@ hr{
|
||||
}
|
||||
|
||||
div.document {
|
||||
background-color: #fafafa;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
div.body {
|
||||
|
||||
@ -16,7 +16,7 @@ We got an updated :doc:`release roadmap <development/roadmap>`!
|
||||
- Support IPv6.
|
||||
- ``addid`` responds properly on errors instead of crashing.
|
||||
- ``commands`` support, which makes RelaXXPlayer work with Mopidy. (Fixes:
|
||||
GH-6)
|
||||
:issue:`6`)
|
||||
- Does no longer crash on invalid data, i.e. non-UTF-8 data.
|
||||
- ``ACK`` error messages are now MPD-compliant, which should make clients
|
||||
handle errors from Mopidy better.
|
||||
@ -31,23 +31,46 @@ We got an updated :doc:`release roadmap <development/roadmap>`!
|
||||
- Having multiple identical tracks in a playlist is now working properly.
|
||||
(CPID refactoring)
|
||||
|
||||
- Despotify backend:
|
||||
|
||||
- Catch and log :exc:`spytify.SpytifyError`. (Fixes: :issue:`11`)
|
||||
|
||||
- Libspotify backend:
|
||||
|
||||
- Fix choppy playback using the Libspotify backend by using blocking ALSA
|
||||
mode. (Fixes: GH-7)
|
||||
mode. (Fixes: :issue:`7`)
|
||||
|
||||
- Backend API:
|
||||
|
||||
- A new data structure called ``cp_track`` is now used in the current
|
||||
playlist controller and the playback controller. A ``cp_track`` is a
|
||||
two-tuple of (CPID integer, :class:`mopidy.models.Track`), identifying an
|
||||
instance of a track uniquely within the current playlist.
|
||||
- :meth:`mopidy.backends.BaseCurrentPlaylistController.load()` now accepts
|
||||
lists of :class:`mopidy.models.Track` instead of
|
||||
:class:`mopidy.models.Playlist`, as none of the other fields on the
|
||||
``Playlist`` model was in use.
|
||||
- :meth:`mopidy.backends.BaseCurrentPlaylistController.remove()` now takes
|
||||
criterias, just like
|
||||
:meth:`mopidy.backends.BaseCurrentPlaylistController.get()`, and not the
|
||||
track to remove.
|
||||
:meth:`mopidy.backends.BaseCurrentPlaylistController.get()`.
|
||||
- :meth:`mopidy.backends.BaseCurrentPlaylistController.get()` now returns a
|
||||
``cp_track``.
|
||||
- :attr:`mopidy.backends.BaseCurrentPlaylistController.tracks` is now
|
||||
read-only. Use the methods to change its contents.
|
||||
- :attr:`mopidy.backends.BaseCurrentPlaylistController.cp_tracks` is a
|
||||
read-only list of ``cp_track``. Use the methods to change its contents.
|
||||
- :attr:`mopidy.backends.BasePlaybackController.current_track` is now
|
||||
just for convenience and read-only. To set the current track, assign a
|
||||
``cp_track`` to
|
||||
:attr:`mopidy.backends.BasePlaybackController.current_cp_track`.
|
||||
- :attr:`mopidy.backends.BasePlaybackController.current_cpid` is the
|
||||
read-only CPID of the current track.
|
||||
- :attr:`mopidy.backends.BasePlaybackController.next_cp_track` is the
|
||||
next ``cp_track`` in the playlist.
|
||||
- :attr:`mopidy.backends.BasePlaybackController.previous_cp_track` is
|
||||
the previous ``cp_track`` in the playlist.
|
||||
- :meth:`mopidy.backends.BasePlaybackController.play()` now takes a
|
||||
``cp_track``.
|
||||
|
||||
|
||||
0.1.0a2 (2010-06-02)
|
||||
@ -86,19 +109,19 @@ As always, report problems at our IRC channel or our issue tracker. Thanks!
|
||||
|
||||
- Backend API changes:
|
||||
|
||||
- Removed ``backend.playback.volume`` wrapper. Use ``backend.mixer.volume``
|
||||
directly.
|
||||
- Renamed ``backend.playback.playlist_position`` to
|
||||
``current_playlist_position`` to match naming of ``current_track``.
|
||||
- Replaced ``get_by_id()`` with a more flexible ``get(**criteria)``.
|
||||
- Removed ``backend.playback.volume`` wrapper. Use ``backend.mixer.volume``
|
||||
directly.
|
||||
- Renamed ``backend.playback.playlist_position`` to
|
||||
``current_playlist_position`` to match naming of ``current_track``.
|
||||
- Replaced ``get_by_id()`` with a more flexible ``get(**criteria)``.
|
||||
|
||||
- Merged the ``gstreamer`` branch from Thomas Adamcik:
|
||||
|
||||
- More than 200 new tests, and thus several bugfixes to existing code.
|
||||
- Several new generic features, like shuffle, consume, and playlist repeat.
|
||||
(Fixes: GH-3)
|
||||
- **[Work in Progress]** A new backend for playing music from a local music
|
||||
archive using the Gstreamer library.
|
||||
- More than 200 new tests, and thus several bugfixes to existing code.
|
||||
- Several new generic features, like shuffle, consume, and playlist repeat.
|
||||
(Fixes: :issue:`3`)
|
||||
- **[Work in Progress]** A new backend for playing music from a local music
|
||||
archive using the Gstreamer library.
|
||||
|
||||
- Made :class:`mopidy.mixers.alsa.AlsaMixer` work on machines without a mixer
|
||||
named "Master".
|
||||
|
||||
@ -26,7 +26,8 @@ import mopidy
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'autodoc_private_members',
|
||||
'sphinx.ext.graphviz', 'sphinx.ext.inheritance_diagram']
|
||||
'sphinx.ext.graphviz', 'sphinx.ext.inheritance_diagram',
|
||||
'sphinx.ext.extlinks', 'sphinx.ext.viewcode']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@ -198,3 +199,7 @@ latex_documents = [
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
||||
|
||||
|
||||
needs_sphinx = '1.0'
|
||||
|
||||
extlinks = {'issue': ('http://github.com/jodal/mopidy/issues#issue/%s', 'GH-')}
|
||||
|
||||
@ -96,30 +96,22 @@ class BaseCurrentPlaylistController(object):
|
||||
pass
|
||||
|
||||
@property
|
||||
def tracks(self):
|
||||
def cp_tracks(self):
|
||||
"""
|
||||
List of :class:`mopidy.model.Track` in the current playlist.
|
||||
List of two-tuples of (CPID integer, :class:`mopidy.models.Track`).
|
||||
|
||||
Read-only.
|
||||
"""
|
||||
return [t[1] for t in self._cp_tracks]
|
||||
return [copy(ct) for ct in self._cp_tracks]
|
||||
|
||||
def _get_cp_track(self, **criteria):
|
||||
matches = self._cp_tracks
|
||||
for (key, value) in criteria.iteritems():
|
||||
if key == 'cpid':
|
||||
matches = filter(lambda ct: ct[0] == value, matches)
|
||||
else:
|
||||
matches = filter(lambda ct: getattr(ct[1], key) == value,
|
||||
matches)
|
||||
if len(matches) == 1:
|
||||
return matches[0]
|
||||
criteria_string = ', '.join(
|
||||
['%s=%s' % (k, v) for (k, v) in criteria.iteritems()])
|
||||
if len(matches) == 0:
|
||||
raise LookupError(u'"%s" match no tracks' % criteria_string)
|
||||
else:
|
||||
raise LookupError(u'"%s" match multiple tracks' % criteria_string)
|
||||
@property
|
||||
def tracks(self):
|
||||
"""
|
||||
List of :class:`mopidy.models.Track` in the current playlist.
|
||||
|
||||
Read-only.
|
||||
"""
|
||||
return [ct[1] for ct in self._cp_tracks]
|
||||
|
||||
def add(self, track, at_position=None):
|
||||
"""
|
||||
@ -142,7 +134,7 @@ class BaseCurrentPlaylistController(object):
|
||||
def clear(self):
|
||||
"""Clear the current playlist."""
|
||||
self.backend.playback.stop()
|
||||
self.backend.playback.current_track = None
|
||||
self.backend.playback.current_cp_track = None
|
||||
self._cp_tracks = []
|
||||
self.version += 1
|
||||
|
||||
@ -162,9 +154,23 @@ class BaseCurrentPlaylistController(object):
|
||||
|
||||
:param criteria: on or more criteria to match by
|
||||
:type criteria: dict
|
||||
:rtype: :class:`mopidy.models.Track`
|
||||
:rtype: two-tuple (CPID integer, :class:`mopidy.models.Track`)
|
||||
"""
|
||||
return self._get_cp_track(**criteria)[1]
|
||||
matches = self._cp_tracks
|
||||
for (key, value) in criteria.iteritems():
|
||||
if key == 'cpid':
|
||||
matches = filter(lambda ct: ct[0] == value, matches)
|
||||
else:
|
||||
matches = filter(lambda ct: getattr(ct[1], key) == value,
|
||||
matches)
|
||||
if len(matches) == 1:
|
||||
return matches[0]
|
||||
criteria_string = ', '.join(
|
||||
['%s=%s' % (k, v) for (k, v) in criteria.iteritems()])
|
||||
if len(matches) == 0:
|
||||
raise LookupError(u'"%s" match no tracks' % criteria_string)
|
||||
else:
|
||||
raise LookupError(u'"%s" match multiple tracks' % criteria_string)
|
||||
|
||||
def load(self, tracks):
|
||||
"""
|
||||
@ -214,13 +220,13 @@ class BaseCurrentPlaylistController(object):
|
||||
"""
|
||||
Remove the track from the current playlist.
|
||||
|
||||
Uses :meth:`get` to lookup the track to remove.
|
||||
Uses :meth:`get()` to lookup the track to remove.
|
||||
|
||||
:param criteria: on or more criteria to match by
|
||||
:type criteria: dict
|
||||
:type track: :class:`mopidy.models.Track`
|
||||
"""
|
||||
cp_track = self._get_cp_track(**criteria)
|
||||
cp_track = self.get(**criteria)
|
||||
position = self._cp_tracks.index(cp_track)
|
||||
del self._cp_tracks[position]
|
||||
self.version += 1
|
||||
@ -336,11 +342,11 @@ class BasePlaybackController(object):
|
||||
#: Tracks are not removed from the playlist.
|
||||
consume = False
|
||||
|
||||
#: The CPID (current playlist ID) of :attr:`current_track`.
|
||||
current_cpid = 0 # TODO Get the correct CPID
|
||||
|
||||
#: The currently playing or selected :class:`mopidy.models.Track`.
|
||||
current_track = None
|
||||
#: The currently playing or selected track
|
||||
#:
|
||||
#: A two-tuple of (CPID integer, :class:`mopidy.models.Track`) or
|
||||
#: :class:`None`.
|
||||
current_cp_track = None
|
||||
|
||||
#: :class:`True`
|
||||
#: Tracks are selected at random from the playlist.
|
||||
@ -373,69 +379,122 @@ class BasePlaybackController(object):
|
||||
"""Cleanup after component."""
|
||||
pass
|
||||
|
||||
@property
|
||||
def current_cpid(self):
|
||||
"""
|
||||
The CPID (current playlist ID) of :attr:`current_track`.
|
||||
|
||||
Read-only. Extracted from :attr:`current_cp_track` for convenience.
|
||||
"""
|
||||
if self.current_cp_track is None:
|
||||
return None
|
||||
return self.current_cp_track[0]
|
||||
|
||||
@property
|
||||
def current_track(self):
|
||||
"""
|
||||
The currently playing or selected :class:`mopidy.models.Track`.
|
||||
|
||||
Read-only. Extracted from :attr:`current_cp_track` for convenience.
|
||||
"""
|
||||
if self.current_cp_track is None:
|
||||
return None
|
||||
return self.current_cp_track[1]
|
||||
|
||||
@property
|
||||
def current_playlist_position(self):
|
||||
"""The position of the current track in the current playlist."""
|
||||
if self.current_track is None:
|
||||
if self.current_cp_track is None:
|
||||
return None
|
||||
try:
|
||||
return self.backend.current_playlist.tracks.index(
|
||||
self.current_track)
|
||||
return self.backend.current_playlist.cp_tracks.index(
|
||||
self.current_cp_track)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def next_track(self):
|
||||
"""
|
||||
The next :class:`mopidy.models.Track` in the playlist.
|
||||
The next track in the playlist.
|
||||
|
||||
A :class:`mopidy.models.Track` extracted from :attr:`next_cp_track` for
|
||||
convenience.
|
||||
"""
|
||||
next_cp_track = self.next_cp_track
|
||||
if next_cp_track is None:
|
||||
return None
|
||||
return next_cp_track[1]
|
||||
|
||||
@property
|
||||
def next_cp_track(self):
|
||||
"""
|
||||
The next track in the playlist.
|
||||
|
||||
A two-tuple of (CPID integer, :class:`mopidy.models.Track`).
|
||||
|
||||
For normal playback this is the next track in the playlist. If repeat
|
||||
is enabled the next track can loop around the playlist. When random is
|
||||
enabled this should be a random track, all tracks should be played once
|
||||
before the list repeats.
|
||||
"""
|
||||
tracks = self.backend.current_playlist.tracks
|
||||
cp_tracks = self.backend.current_playlist.cp_tracks
|
||||
|
||||
if not tracks:
|
||||
if not cp_tracks:
|
||||
return None
|
||||
|
||||
if self.random and not self._shuffled:
|
||||
if self.repeat or self._first_shuffle:
|
||||
logger.debug('Shuffling tracks')
|
||||
self._shuffled = tracks
|
||||
self._shuffled = cp_tracks
|
||||
random.shuffle(self._shuffled)
|
||||
self._first_shuffle = False
|
||||
|
||||
if self._shuffled:
|
||||
return self._shuffled[0]
|
||||
|
||||
if self.current_track is None:
|
||||
return tracks[0]
|
||||
if self.current_cp_track is None:
|
||||
return cp_tracks[0]
|
||||
|
||||
if self.repeat:
|
||||
return tracks[(self.current_playlist_position + 1) % len(tracks)]
|
||||
return cp_tracks[
|
||||
(self.current_playlist_position + 1) % len(cp_tracks)]
|
||||
|
||||
try:
|
||||
return tracks[self.current_playlist_position + 1]
|
||||
return cp_tracks[self.current_playlist_position + 1]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def previous_track(self):
|
||||
"""
|
||||
The previous :class:`mopidy.models.Track` in the playlist.
|
||||
The previous track in the playlist.
|
||||
|
||||
A :class:`mopidy.models.Track` extracted from :attr:`previous_cp_track`
|
||||
for convenience.
|
||||
"""
|
||||
previous_cp_track = self.previous_cp_track
|
||||
if previous_cp_track is None:
|
||||
return None
|
||||
return previous_cp_track[1]
|
||||
|
||||
@property
|
||||
def previous_cp_track(self):
|
||||
"""
|
||||
The previous track in the playlist.
|
||||
|
||||
A two-tuple of (CPID integer, :class:`mopidy.models.Track`).
|
||||
|
||||
For normal playback this is the previous track in the playlist. If
|
||||
random and/or consume is enabled it should return the current track
|
||||
instead.
|
||||
"""
|
||||
if self.repeat or self.consume or self.random:
|
||||
return self.current_track
|
||||
return self.current_cp_track
|
||||
|
||||
if self.current_track is None or self.current_playlist_position == 0:
|
||||
if self.current_cp_track is None or self.current_playlist_position == 0:
|
||||
return None
|
||||
|
||||
return self.backend.current_playlist.tracks[
|
||||
return self.backend.current_playlist.cp_tracks[
|
||||
self.current_playlist_position - 1]
|
||||
|
||||
@property
|
||||
@ -505,11 +564,11 @@ class BasePlaybackController(object):
|
||||
Typically called by :class:`mopidy.process.CoreProcess` after a message
|
||||
from a library thread is received.
|
||||
"""
|
||||
if self.next_track is not None:
|
||||
if self.next_cp_track is not None:
|
||||
self.next()
|
||||
else:
|
||||
self.stop()
|
||||
self.current_track = None
|
||||
self.current_cp_track = None
|
||||
|
||||
def new_playlist_loaded_callback(self):
|
||||
"""
|
||||
@ -518,7 +577,7 @@ class BasePlaybackController(object):
|
||||
Typically called by :class:`mopidy.process.CoreProcess` after a message
|
||||
from a library thread is received.
|
||||
"""
|
||||
self.current_track = None
|
||||
self.current_cp_track = None
|
||||
self._first_shuffle = True
|
||||
self._shuffled = []
|
||||
|
||||
@ -532,23 +591,23 @@ class BasePlaybackController(object):
|
||||
|
||||
def next(self):
|
||||
"""Play the next track."""
|
||||
original_track = self.current_track
|
||||
original_cp_track = self.current_cp_track
|
||||
|
||||
if self.state == self.STOPPED:
|
||||
return
|
||||
elif self.next_track is not None and self._next(self.next_track):
|
||||
self.current_track = self.next_track
|
||||
elif self.next_cp_track is not None and self._next(self.next_track):
|
||||
self.current_cp_track = self.next_cp_track
|
||||
self.state = self.PLAYING
|
||||
elif self.next_track is None:
|
||||
elif self.next_cp_track is None:
|
||||
self.stop()
|
||||
self.current_track = None
|
||||
self.current_cp_track = None
|
||||
|
||||
# FIXME handle in play aswell?
|
||||
if self.consume:
|
||||
self.backend.current_playlist.remove(id=original_track.id)
|
||||
self.backend.current_playlist.remove(cpid=original_cp_track[0])
|
||||
|
||||
if self.random and self.current_track in self._shuffled:
|
||||
self._shuffled.remove(self.current_track)
|
||||
if self.random and self.current_cp_track in self._shuffled:
|
||||
self._shuffled.remove(self.current_cp_track)
|
||||
|
||||
def _next(self, track):
|
||||
return self._play(track)
|
||||
@ -561,41 +620,42 @@ class BasePlaybackController(object):
|
||||
def _pause(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def play(self, track=None):
|
||||
def play(self, cp_track=None):
|
||||
"""
|
||||
Play the given track or the currently active track.
|
||||
|
||||
:param track: track to play
|
||||
:type track: :class:`mopidy.models.Track` or :class:`None`
|
||||
:param cp_track: track to play
|
||||
:type cp_track: two-tuple (CPID integer, :class:`mopidy.models.Track`)
|
||||
or :class:`None`
|
||||
"""
|
||||
|
||||
if track:
|
||||
assert track in self.backend.current_playlist.tracks
|
||||
elif not self.current_track:
|
||||
track = self.next_track
|
||||
if cp_track is not None:
|
||||
assert cp_track in self.backend.current_playlist.cp_tracks
|
||||
elif not self.current_cp_track:
|
||||
cp_track = self.next_cp_track
|
||||
|
||||
if self.state == self.PAUSED and track is None:
|
||||
if self.state == self.PAUSED and cp_track is None:
|
||||
self.resume()
|
||||
elif track is not None and self._play(track):
|
||||
self.current_track = track
|
||||
elif cp_track is not None and self._play(cp_track[1]):
|
||||
self.current_cp_track = cp_track
|
||||
self.state = self.PLAYING
|
||||
|
||||
# TODO Do something sensible when _play() returns False, like calling
|
||||
# next(). Adding this todo instead of just implementing it as I want a
|
||||
# test case first.
|
||||
|
||||
if self.random and self.current_track in self._shuffled:
|
||||
self._shuffled.remove(self.current_track)
|
||||
if self.random and self.current_cp_track in self._shuffled:
|
||||
self._shuffled.remove(self.current_cp_track)
|
||||
|
||||
def _play(self, track):
|
||||
raise NotImplementedError
|
||||
|
||||
def previous(self):
|
||||
"""Play the previous track."""
|
||||
if (self.previous_track is not None
|
||||
if (self.previous_cp_track is not None
|
||||
and self.state != self.STOPPED
|
||||
and self._previous(self.previous_track)):
|
||||
self.current_track = self.previous_track
|
||||
self.current_cp_track = self.previous_cp_track
|
||||
self.state = self.PLAYING
|
||||
|
||||
def _previous(self, track):
|
||||
|
||||
@ -79,20 +79,36 @@ class DespotifyLibraryController(BaseLibraryController):
|
||||
|
||||
class DespotifyPlaybackController(BasePlaybackController):
|
||||
def _pause(self):
|
||||
self.backend.spotify.pause()
|
||||
return True
|
||||
try:
|
||||
self.backend.spotify.pause()
|
||||
return True
|
||||
except spytify.SpytifyError as e:
|
||||
logger.error(e)
|
||||
return False
|
||||
|
||||
def _play(self, track):
|
||||
self.backend.spotify.play(self.backend.spotify.lookup(track.uri))
|
||||
return True
|
||||
try:
|
||||
self.backend.spotify.play(self.backend.spotify.lookup(track.uri))
|
||||
return True
|
||||
except spytify.SpytifyError as e:
|
||||
logger.error(e)
|
||||
return False
|
||||
|
||||
def _resume(self):
|
||||
self.backend.spotify.resume()
|
||||
return True
|
||||
try:
|
||||
self.backend.spotify.resume()
|
||||
return True
|
||||
except spytify.SpytifyError as e:
|
||||
logger.error(e)
|
||||
return False
|
||||
|
||||
def _stop(self):
|
||||
self.backend.spotify.stop()
|
||||
return True
|
||||
try:
|
||||
self.backend.spotify.stop()
|
||||
return True
|
||||
except spytify.SpytifyError as e:
|
||||
logger.error(e)
|
||||
return False
|
||||
|
||||
|
||||
class DespotifyStoredPlaylistsController(BaseStoredPlaylistsController):
|
||||
@ -149,7 +165,8 @@ class DespotifyTranslator(object):
|
||||
return Playlist(
|
||||
uri=spotify_playlist.get_uri(),
|
||||
name=spotify_playlist.name.decode(ENCODING),
|
||||
tracks=filter(None, [cls.to_mopidy_track(t) for t in spotify_playlist.tracks]),
|
||||
tracks=filter(None,
|
||||
[cls.to_mopidy_track(t) for t in spotify_playlist.tracks]),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -391,8 +391,8 @@ class MpdFrontend(object):
|
||||
"""
|
||||
cpid = int(cpid)
|
||||
to = int(to)
|
||||
track = self.backend.current_playlist.get(cpid=cpid)
|
||||
position = self.backend.current_playlist.tracks.index(track)
|
||||
cp_track = self.backend.current_playlist.get(cpid=cpid)
|
||||
position = self.backend.current_playlist.cp_tracks.index(cp_track)
|
||||
self.backend.current_playlist.move(position, position + 1, to)
|
||||
|
||||
@handle_pattern(r'^playlist$')
|
||||
@ -426,8 +426,8 @@ class MpdFrontend(object):
|
||||
"""
|
||||
if tag == 'filename':
|
||||
try:
|
||||
track = self.backend.current_playlist.get(uri=needle)
|
||||
return track.mpd_format()
|
||||
cp_track = self.backend.current_playlist.get(uri=needle)
|
||||
return cp_track[1].mpd_format()
|
||||
except LookupError:
|
||||
return None
|
||||
raise MpdNotImplemented # TODO
|
||||
@ -445,9 +445,10 @@ class MpdFrontend(object):
|
||||
if cpid is not None:
|
||||
try:
|
||||
cpid = int(cpid)
|
||||
track = self.backend.current_playlist.get(cpid=cpid)
|
||||
position = self.backend.current_playlist.tracks.index(track)
|
||||
return track.mpd_format(position=position, cpid=cpid)
|
||||
cp_track = self.backend.current_playlist.get(cpid=cpid)
|
||||
position = self.backend.current_playlist.cp_tracks.index(
|
||||
cp_track)
|
||||
return cp_track[1].mpd_format(position=position, cpid=cpid)
|
||||
except LookupError:
|
||||
raise MpdNoExistError(u'No such song', command=u'playlistid')
|
||||
else:
|
||||
@ -593,10 +594,10 @@ class MpdFrontend(object):
|
||||
"""
|
||||
cpid1 = int(cpid1)
|
||||
cpid2 = int(cpid2)
|
||||
track1 = self.backend.current_playlist.get(cpid=cpid1)
|
||||
track2 = self.backend.current_playlist.get(cpid=cpid2)
|
||||
position1 = self.backend.current_playlist.tracks.index(track1)
|
||||
position2 = self.backend.current_playlist.tracks.index(track2)
|
||||
cp_track1 = self.backend.current_playlist.get(cpid=cpid1)
|
||||
cp_track2 = self.backend.current_playlist.get(cpid=cpid2)
|
||||
position1 = self.backend.current_playlist.cp_tracks.index(cp_track1)
|
||||
position2 = self.backend.current_playlist.cp_tracks.index(cp_track2)
|
||||
self._current_playlist_swap(position1, position2)
|
||||
|
||||
@handle_pattern(r'^$')
|
||||
@ -949,10 +950,10 @@ class MpdFrontend(object):
|
||||
cpid = int(cpid)
|
||||
try:
|
||||
if cpid == -1:
|
||||
track = self.backend.current_playlist.tracks[0]
|
||||
cp_track = self.backend.current_playlist.cp_tracks[0]
|
||||
else:
|
||||
track = self.backend.current_playlist.get(cpid=cpid)
|
||||
return self.backend.playback.play(track)
|
||||
cp_track = self.backend.current_playlist.get(cpid=cpid)
|
||||
return self.backend.playback.play(cp_track)
|
||||
except LookupError:
|
||||
raise MpdNoExistError(u'No such song', command=u'playid')
|
||||
|
||||
@ -968,15 +969,16 @@ class MpdFrontend(object):
|
||||
|
||||
*MPoD:*
|
||||
|
||||
- issues ``play "-1"`` after playlist replacement.
|
||||
- issues ``play "-1"`` after playlist replacement to start playback at
|
||||
the first track.
|
||||
"""
|
||||
songpos = int(songpos)
|
||||
try:
|
||||
if songpos == -1:
|
||||
track = self.backend.current_playlist.tracks[0]
|
||||
cp_track = self.backend.current_playlist.cp_tracks[0]
|
||||
else:
|
||||
track = self.backend.current_playlist.tracks[songpos]
|
||||
return self.backend.playback.play(track)
|
||||
cp_track = self.backend.current_playlist.cp_tracks[songpos]
|
||||
return self.backend.playback.play(cp_track)
|
||||
except IndexError:
|
||||
raise MpdArgError(u'Bad song index', command=u'play')
|
||||
|
||||
@ -1400,9 +1402,8 @@ class MpdFrontend(object):
|
||||
return int(self.backend.playback.single)
|
||||
|
||||
def __status_status_songid(self):
|
||||
# TODO Replace track.id with CPID
|
||||
if self.backend.playback.current_track.id is not None:
|
||||
return self.backend.playback.current_track.id
|
||||
if self.backend.playback.current_cpid is not None:
|
||||
return self.backend.playback.current_cpid
|
||||
else:
|
||||
return self.__status_status_songpos()
|
||||
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
Sphinx
|
||||
Sphinx >= 1.0
|
||||
pygraphviz
|
||||
|
||||
@ -63,14 +63,13 @@ class BaseCurrentPlaylistControllerTest(object):
|
||||
|
||||
@populate_playlist
|
||||
def test_get_by_cpid(self):
|
||||
track = self.controller.tracks[1]
|
||||
cpid = self.controller._cp_tracks[1][0] # XXX Messing in internals
|
||||
self.assertEqual(track, self.controller.get(cpid=cpid))
|
||||
cp_track = self.controller.cp_tracks[1]
|
||||
self.assertEqual(cp_track, self.controller.get(cpid=cp_track[0]))
|
||||
|
||||
@populate_playlist
|
||||
def test_get_by_id(self):
|
||||
track = self.controller.tracks[1]
|
||||
self.assertEqual(track, self.controller.get(id=track.id))
|
||||
cp_track = self.controller.cp_tracks[1]
|
||||
self.assertEqual(cp_track, self.controller.get(id=cp_track[1].id))
|
||||
|
||||
@populate_playlist
|
||||
def test_get_by_id_raises_error_for_invalid_id(self):
|
||||
@ -78,8 +77,8 @@ class BaseCurrentPlaylistControllerTest(object):
|
||||
|
||||
@populate_playlist
|
||||
def test_get_by_uri(self):
|
||||
track = self.controller.tracks[1]
|
||||
self.assertEqual(track, self.controller.get(uri=track.uri))
|
||||
cp_track = self.controller.cp_tracks[1]
|
||||
self.assertEqual(cp_track, self.controller.get(uri=cp_track[1].uri))
|
||||
|
||||
@populate_playlist
|
||||
def test_get_by_uri_raises_error_for_invalid_id(self):
|
||||
@ -111,7 +110,7 @@ class BaseCurrentPlaylistControllerTest(object):
|
||||
def test_get_by_id_returns_unique_match(self):
|
||||
track = Track(id=1)
|
||||
self.controller.load([Track(id=13), track, Track(id=17)])
|
||||
self.assertEqual(track, self.controller.get(id=1))
|
||||
self.assertEqual(track, self.controller.get(id=1)[1])
|
||||
|
||||
def test_get_by_id_raises_error_if_multiple_matches(self):
|
||||
track = Track(id=1)
|
||||
@ -133,7 +132,7 @@ class BaseCurrentPlaylistControllerTest(object):
|
||||
def test_get_by_uri_returns_unique_match(self):
|
||||
track = Track(uri='a')
|
||||
self.controller.load([Track(uri='z'), track, Track(uri='y')])
|
||||
self.assertEqual(track, self.controller.get(uri='a'))
|
||||
self.assertEqual(track, self.controller.get(uri='a')[1])
|
||||
|
||||
def test_get_by_uri_raises_error_if_multiple_matches(self):
|
||||
track = Track(uri='a')
|
||||
@ -158,16 +157,16 @@ class BaseCurrentPlaylistControllerTest(object):
|
||||
track2 = Track(id=1, uri='b')
|
||||
track3 = Track(id=2, uri='b')
|
||||
self.controller.load([track1, track2, track3])
|
||||
self.assertEqual(track1, self.controller.get(id=1, uri='a'))
|
||||
self.assertEqual(track2, self.controller.get(id=1, uri='b'))
|
||||
self.assertEqual(track3, self.controller.get(id=2, uri='b'))
|
||||
self.assertEqual(track1, self.controller.get(id=1, uri='a')[1])
|
||||
self.assertEqual(track2, self.controller.get(id=1, uri='b')[1])
|
||||
self.assertEqual(track3, self.controller.get(id=2, uri='b')[1])
|
||||
|
||||
def test_get_by_criteria_that_is_not_present_in_all_elements(self):
|
||||
track1 = Track(id=1)
|
||||
track2 = Track(uri='b')
|
||||
track3 = Track(id=2)
|
||||
self.controller.load([track1, track2, track3])
|
||||
self.assertEqual(track1, self.controller.get(id=1))
|
||||
self.assertEqual(track1, self.controller.get(id=1)[1])
|
||||
|
||||
@populate_playlist
|
||||
def test_load_replaces_playlist(self):
|
||||
@ -316,6 +315,7 @@ class BasePlaybackControllerTest(object):
|
||||
def setUp(self):
|
||||
self.backend = self.backend_class(mixer=DummyMixer())
|
||||
self.playback = self.backend.playback
|
||||
self.current_playlist = self.backend.current_playlist
|
||||
|
||||
assert len(self.tracks) >= 3, \
|
||||
'Need at least three tracks to run tests.'
|
||||
@ -349,12 +349,13 @@ class BasePlaybackControllerTest(object):
|
||||
@populate_playlist
|
||||
def test_play_track_state(self):
|
||||
self.assertEqual(self.playback.state, self.playback.STOPPED)
|
||||
self.playback.play(self.tracks[-1])
|
||||
self.playback.play(self.current_playlist.cp_tracks[-1])
|
||||
self.assertEqual(self.playback.state, self.playback.PLAYING)
|
||||
|
||||
@populate_playlist
|
||||
def test_play_track_return_value(self):
|
||||
self.assertEqual(self.playback.play(self.tracks[-1]), None)
|
||||
self.assertEqual(self.playback.play(
|
||||
self.current_playlist.cp_tracks[-1]), None)
|
||||
|
||||
@populate_playlist
|
||||
def test_play_when_playing(self):
|
||||
@ -379,17 +380,17 @@ class BasePlaybackControllerTest(object):
|
||||
|
||||
@populate_playlist
|
||||
def test_play_track_sets_current_track(self):
|
||||
self.playback.play(self.tracks[-1])
|
||||
self.playback.play(self.current_playlist.cp_tracks[-1])
|
||||
self.assertEqual(self.playback.current_track, self.tracks[-1])
|
||||
|
||||
@populate_playlist
|
||||
def test_current_track_after_completed_playlist(self):
|
||||
self.playback.play(self.tracks[-1])
|
||||
self.playback.play(self.current_playlist.cp_tracks[-1])
|
||||
self.playback.end_of_track_callback()
|
||||
self.assertEqual(self.playback.state, self.playback.STOPPED)
|
||||
self.assertEqual(self.playback.current_track, None)
|
||||
|
||||
self.playback.play(self.tracks[-1])
|
||||
self.playback.play(self.current_playlist.cp_tracks[-1])
|
||||
self.playback.next()
|
||||
self.assertEqual(self.playback.state, self.playback.STOPPED)
|
||||
self.assertEqual(self.playback.current_track, None)
|
||||
@ -510,7 +511,7 @@ class BasePlaybackControllerTest(object):
|
||||
@populate_playlist
|
||||
def test_next_track_at_end_of_playlist(self):
|
||||
self.playback.play()
|
||||
for track in self.tracks[1:]:
|
||||
for track in self.current_playlist.cp_tracks[1:]:
|
||||
self.playback.next()
|
||||
self.assertEqual(self.playback.next_track, None)
|
||||
|
||||
@ -564,7 +565,7 @@ class BasePlaybackControllerTest(object):
|
||||
|
||||
@populate_playlist
|
||||
def test_previous_track_with_random(self):
|
||||
self.playback.repeat = True
|
||||
self.playback.random = True
|
||||
for track in self.tracks:
|
||||
self.playback.next()
|
||||
self.assertEqual(self.playback.previous_track,
|
||||
@ -602,7 +603,7 @@ class BasePlaybackControllerTest(object):
|
||||
|
||||
@populate_playlist
|
||||
def test_current_playlist_position_at_end_of_playlist(self):
|
||||
self.playback.play(self.tracks[-1])
|
||||
self.playback.play(self.current_playlist.cp_tracks[-1])
|
||||
self.playback.end_of_track_callback()
|
||||
self.assertEqual(self.playback.current_playlist_position, None)
|
||||
|
||||
@ -763,8 +764,8 @@ class BasePlaybackControllerTest(object):
|
||||
|
||||
@populate_playlist
|
||||
def test_seek_beyond_end_of_song_for_last_track(self):
|
||||
self.playback.play(self.tracks[-1])
|
||||
self.playback.seek(self.tracks[-1].length*100)
|
||||
self.playback.play(self.current_playlist.cp_tracks[-1])
|
||||
self.playback.seek(self.current_playlist.tracks[-1].length * 100)
|
||||
self.assertEqual(self.playback.state, self.playback.STOPPED)
|
||||
|
||||
@populate_playlist
|
||||
@ -884,7 +885,7 @@ class BasePlaybackControllerTest(object):
|
||||
|
||||
@populate_playlist
|
||||
def test_end_of_playlist_stops(self):
|
||||
self.playback.play(self.tracks[-1])
|
||||
self.playback.play(self.current_playlist.cp_tracks[-1])
|
||||
self.playback.end_of_track_callback()
|
||||
self.assertEqual(self.playback.state, self.playback.STOPPED)
|
||||
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.mixers.denon import DenonMixer
|
||||
from tests.mixers.dummy_test import BaseMixerTest
|
||||
from tests.mixers.base_test import BaseMixerTest
|
||||
|
||||
class DenonMixerDeviceMock(object):
|
||||
def __init__(self):
|
||||
|
||||
26
tests/mpd/audio_output_test.py
Normal file
26
tests/mpd/audio_output_test.py
Normal file
@ -0,0 +1,26 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class AudioOutputHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_enableoutput(self):
|
||||
result = self.h.handle_request(u'enableoutput "0"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_disableoutput(self):
|
||||
result = self.h.handle_request(u'disableoutput "0"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_outputs(self):
|
||||
result = self.h.handle_request(u'outputs')
|
||||
self.assert_(u'outputid: 0' in result)
|
||||
self.assert_(u'outputname: DummyBackend' in result)
|
||||
self.assert_(u'outputenabled: 1' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
58
tests/mpd/command_list_test.py
Normal file
58
tests/mpd/command_list_test.py
Normal file
@ -0,0 +1,58 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class CommandListsTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_command_list_begin(self):
|
||||
result = self.h.handle_request(u'command_list_begin')
|
||||
self.assert_(result is None)
|
||||
|
||||
def test_command_list_end(self):
|
||||
self.h.handle_request(u'command_list_begin')
|
||||
result = self.h.handle_request(u'command_list_end')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_command_list_end_without_start_first_is_an_unknown_command(self):
|
||||
result = self.h.handle_request(u'command_list_end')
|
||||
self.assertEquals(result[0],
|
||||
u'ACK [5@0] {} unknown command "command_list_end"')
|
||||
|
||||
def test_command_list_with_ping(self):
|
||||
self.h.handle_request(u'command_list_begin')
|
||||
self.assertEqual([], self.h.command_list)
|
||||
self.assertEqual(False, self.h.command_list_ok)
|
||||
self.h.handle_request(u'ping')
|
||||
self.assert_(u'ping' in self.h.command_list)
|
||||
result = self.h.handle_request(u'command_list_end')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(False, self.h.command_list)
|
||||
|
||||
def test_command_list_with_error_returns_ack_with_correct_index(self):
|
||||
self.h.handle_request(u'command_list_begin')
|
||||
self.h.handle_request(u'play') # Known command
|
||||
self.h.handle_request(u'paly') # Unknown command
|
||||
result = self.h.handle_request(u'command_list_end')
|
||||
self.assertEqual(result[0], u'ACK [5@1] {} unknown command "paly"')
|
||||
|
||||
def test_command_list_ok_begin(self):
|
||||
result = self.h.handle_request(u'command_list_ok_begin')
|
||||
self.assert_(result is None)
|
||||
|
||||
def test_command_list_ok_with_ping(self):
|
||||
self.h.handle_request(u'command_list_ok_begin')
|
||||
self.assertEqual([], self.h.command_list)
|
||||
self.assertEqual(True, self.h.command_list_ok)
|
||||
self.h.handle_request(u'ping')
|
||||
self.assert_(u'ping' in self.h.command_list)
|
||||
result = self.h.handle_request(u'command_list_end')
|
||||
self.assert_(u'list_OK' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(False, self.h.command_list)
|
||||
self.assertEqual(False, self.h.command_list_ok)
|
||||
31
tests/mpd/connection_test.py
Normal file
31
tests/mpd/connection_test.py
Normal file
@ -0,0 +1,31 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class ConnectionHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_close(self):
|
||||
result = self.h.handle_request(u'close')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_empty_request(self):
|
||||
result = self.h.handle_request(u'')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_kill(self):
|
||||
result = self.h.handle_request(u'kill')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_password(self):
|
||||
result = self.h.handle_request(u'password "secret"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_ping(self):
|
||||
result = self.h.handle_request(u'ping')
|
||||
self.assert_(u'OK' in result)
|
||||
393
tests/mpd/current_playlist_test.py
Normal file
393
tests/mpd/current_playlist_test.py
Normal file
@ -0,0 +1,393 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.models import Track
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class CurrentPlaylistHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_add(self):
|
||||
needle = Track(uri='dummy://foo')
|
||||
self.b.library._library = [Track(), Track(), needle, Track()]
|
||||
self.b.current_playlist.load(
|
||||
[Track(), Track(), Track(), Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'add "dummy://foo"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 6)
|
||||
self.assertEqual(self.b.current_playlist.tracks[5], needle)
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_add_with_uri_not_found_in_library_should_ack(self):
|
||||
result = self.h.handle_request(u'add "dummy://foo"')
|
||||
self.assertEqual(result[0],
|
||||
u'ACK [50@0] {add} directory or file not found')
|
||||
|
||||
def test_addid_without_songpos(self):
|
||||
needle = Track(uri='dummy://foo', id=137)
|
||||
self.b.library._library = [Track(), Track(), needle, Track()]
|
||||
self.b.current_playlist.load(
|
||||
[Track(), Track(), Track(), Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'addid "dummy://foo"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 6)
|
||||
self.assertEqual(self.b.current_playlist.tracks[5], needle)
|
||||
self.assert_(u'Id: 137' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_addid_with_songpos(self):
|
||||
needle = Track(uri='dummy://foo', id=137)
|
||||
self.b.library._library = [Track(), Track(), needle, Track()]
|
||||
self.b.current_playlist.load(
|
||||
[Track(), Track(), Track(), Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'addid "dummy://foo" "3"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 6)
|
||||
self.assertEqual(self.b.current_playlist.tracks[3], needle)
|
||||
self.assert_(u'Id: 137' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_addid_with_songpos_out_of_bounds_should_ack(self):
|
||||
needle = Track(uri='dummy://foo', id=137)
|
||||
self.b.library._library = [Track(), Track(), needle, Track()]
|
||||
self.b.current_playlist.load(
|
||||
[Track(), Track(), Track(), Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'addid "dummy://foo" "6"')
|
||||
self.assertEqual(result[0], u'ACK [2@0] {addid} Bad song index')
|
||||
|
||||
def test_addid_with_uri_not_found_in_library_should_ack(self):
|
||||
result = self.h.handle_request(u'addid "dummy://foo"')
|
||||
self.assertEqual(result[0], u'ACK [50@0] {addid} No such song')
|
||||
|
||||
def test_clear(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(), Track(), Track(), Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'clear')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 0)
|
||||
self.assertEqual(self.b.playback.current_track, None)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_delete_songpos(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(id=1), Track(id=2), Track(id=3), Track(id=4), Track(id=5)])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'delete "2"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 4)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_delete_songpos_out_of_bounds(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(), Track(), Track(), Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'delete "5"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
self.assertEqual(result[0], u'ACK [2@0] {delete} Bad song index')
|
||||
|
||||
def test_delete_open_range(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(id=1), Track(id=2), Track(id=3), Track(id=4), Track(id=5)])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'delete "1:"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 1)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_delete_closed_range(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(id=1), Track(id=2), Track(id=3), Track(id=4), Track(id=5)])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'delete "1:3"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 3)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_delete_range_out_of_bounds(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(), Track(), Track(), Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
result = self.h.handle_request(u'delete "5:7"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 5)
|
||||
self.assertEqual(result[0], u'ACK [2@0] {delete} Bad song index')
|
||||
|
||||
def test_deleteid(self):
|
||||
self.b.current_playlist.load([Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 2)
|
||||
result = self.h.handle_request(u'deleteid "2"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 1)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_deleteid_does_not_exist(self):
|
||||
self.b.current_playlist.load([Track(), Track()])
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 2)
|
||||
result = self.h.handle_request(u'deleteid "12345"')
|
||||
self.assertEqual(len(self.b.current_playlist.tracks), 2)
|
||||
self.assertEqual(result[0], u'ACK [50@0] {deleteid} No such song')
|
||||
|
||||
def test_move_songpos(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'move "1" "0"')
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'b')
|
||||
self.assertEqual(self.b.current_playlist.tracks[1].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[2].name, 'c')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'd')
|
||||
self.assertEqual(self.b.current_playlist.tracks[4].name, 'e')
|
||||
self.assertEqual(self.b.current_playlist.tracks[5].name, 'f')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_move_open_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'move "2:" "0"')
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'c')
|
||||
self.assertEqual(self.b.current_playlist.tracks[1].name, 'd')
|
||||
self.assertEqual(self.b.current_playlist.tracks[2].name, 'e')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'f')
|
||||
self.assertEqual(self.b.current_playlist.tracks[4].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[5].name, 'b')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_move_closed_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'move "1:3" "0"')
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'b')
|
||||
self.assertEqual(self.b.current_playlist.tracks[1].name, 'c')
|
||||
self.assertEqual(self.b.current_playlist.tracks[2].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'd')
|
||||
self.assertEqual(self.b.current_playlist.tracks[4].name, 'e')
|
||||
self.assertEqual(self.b.current_playlist.tracks[5].name, 'f')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_moveid(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'moveid "5" "2"')
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[1].name, 'b')
|
||||
self.assertEqual(self.b.current_playlist.tracks[2].name, 'e')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'c')
|
||||
self.assertEqual(self.b.current_playlist.tracks[4].name, 'd')
|
||||
self.assertEqual(self.b.current_playlist.tracks[5].name, 'f')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlist_returns_same_as_playlistinfo(self):
|
||||
playlist_result = self.h.handle_request(u'playlist')
|
||||
playlistinfo_result = self.h.handle_request(u'playlistinfo')
|
||||
self.assertEqual(playlist_result, playlistinfo_result)
|
||||
|
||||
def test_playlistfind(self):
|
||||
result = self.h.handle_request(u'playlistfind "tag" "needle"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_playlistfind_by_filename(self):
|
||||
result = self.h.handle_request(
|
||||
u'playlistfind "filename" "file:///dev/null"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistfind_by_filename_without_quotes(self):
|
||||
result = self.h.handle_request(
|
||||
u'playlistfind filename "file:///dev/null"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistfind_by_filename_in_current_playlist(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(uri='file:///exists')])
|
||||
result = self.h.handle_request(
|
||||
u'playlistfind filename "file:///exists"')
|
||||
self.assert_(u'file: file:///exists' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistid_without_songid(self):
|
||||
self.b.current_playlist.load([Track(name='a'), Track(name='b')])
|
||||
result = self.h.handle_request(u'playlistid')
|
||||
self.assert_(u'Title: a' in result)
|
||||
self.assert_(u'Title: b' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistid_with_songid(self):
|
||||
self.b.current_playlist.load([Track(name='a'), Track(name='b')])
|
||||
result = self.h.handle_request(u'playlistid "2"')
|
||||
self.assert_(u'Title: a' not in result)
|
||||
self.assert_(u'Id: 1' not in result)
|
||||
self.assert_(u'Title: b' in result)
|
||||
self.assert_(u'Id: 2' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistid_with_not_existing_songid_fails(self):
|
||||
self.b.current_playlist.load([Track(name='a'), Track(name='b')])
|
||||
result = self.h.handle_request(u'playlistid "25"')
|
||||
self.assertEqual(result[0], u'ACK [50@0] {playlistid} No such song')
|
||||
|
||||
def test_playlistinfo_without_songpos_or_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'playlistinfo')
|
||||
self.assert_(u'Title: a' in result)
|
||||
self.assert_(u'Title: b' in result)
|
||||
self.assert_(u'Title: c' in result)
|
||||
self.assert_(u'Title: d' in result)
|
||||
self.assert_(u'Title: e' in result)
|
||||
self.assert_(u'Title: f' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistinfo_with_songpos(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'playlistinfo "4"')
|
||||
self.assert_(u'Title: a' not in result)
|
||||
self.assert_(u'Title: b' not in result)
|
||||
self.assert_(u'Title: c' not in result)
|
||||
self.assert_(u'Title: d' not in result)
|
||||
self.assert_(u'Title: e' in result)
|
||||
self.assert_(u'Title: f' not in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistinfo_with_negative_songpos_same_as_playlistinfo(self):
|
||||
result1 = self.h.handle_request(u'playlistinfo "-1"')
|
||||
result2 = self.h.handle_request(u'playlistinfo')
|
||||
self.assertEqual(result1, result2)
|
||||
|
||||
def test_playlistinfo_with_open_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'playlistinfo "2:"')
|
||||
self.assert_(u'Title: a' not in result)
|
||||
self.assert_(u'Title: b' not in result)
|
||||
self.assert_(u'Title: c' in result)
|
||||
self.assert_(u'Title: d' in result)
|
||||
self.assert_(u'Title: e' in result)
|
||||
self.assert_(u'Title: f' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistinfo_with_closed_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'playlistinfo "2:4"')
|
||||
self.assert_(u'Title: a' not in result)
|
||||
self.assert_(u'Title: b' not in result)
|
||||
self.assert_(u'Title: c' in result)
|
||||
self.assert_(u'Title: d' in result)
|
||||
self.assert_(u'Title: e' not in result)
|
||||
self.assert_(u'Title: f' not in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistinfo_with_too_high_start_of_range_returns_arg_error(self):
|
||||
result = self.h.handle_request(u'playlistinfo "10:20"')
|
||||
self.assert_(u'ACK [2@0] {playlistinfo} Bad song index' in result)
|
||||
|
||||
def test_playlistinfo_with_too_high_end_of_range_returns_ok(self):
|
||||
result = self.h.handle_request(u'playlistinfo "0:20"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_playlistsearch(self):
|
||||
result = self.h.handle_request(u'playlistsearch "tag" "needle"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_plchanges(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(name='a'), Track(name='b'), Track(name='c')])
|
||||
result = self.h.handle_request(u'plchanges "0"')
|
||||
self.assert_(u'Title: a' in result)
|
||||
self.assert_(u'Title: b' in result)
|
||||
self.assert_(u'Title: c' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_plchangesposid(self):
|
||||
self.b.current_playlist.load(
|
||||
[Track(id=11), Track(id=12), Track(id=13)])
|
||||
result = self.h.handle_request(u'plchangesposid "0"')
|
||||
self.assert_(u'cpos: 0' in result)
|
||||
self.assert_(u'Id: 11' in result)
|
||||
self.assert_(u'cpos: 2' in result)
|
||||
self.assert_(u'Id: 12' in result)
|
||||
self.assert_(u'cpos: 2' in result)
|
||||
self.assert_(u'Id: 13' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_shuffle_without_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
version = self.b.current_playlist.version
|
||||
result = self.h.handle_request(u'shuffle')
|
||||
self.assert_(version < self.b.current_playlist.version)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_shuffle_with_open_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
version = self.b.current_playlist.version
|
||||
result = self.h.handle_request(u'shuffle "4:"')
|
||||
self.assert_(version < self.b.current_playlist.version)
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[1].name, 'b')
|
||||
self.assertEqual(self.b.current_playlist.tracks[2].name, 'c')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'd')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_shuffle_with_closed_range(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
version = self.b.current_playlist.version
|
||||
result = self.h.handle_request(u'shuffle "1:3"')
|
||||
self.assert_(version < self.b.current_playlist.version)
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'd')
|
||||
self.assertEqual(self.b.current_playlist.tracks[4].name, 'e')
|
||||
self.assertEqual(self.b.current_playlist.tracks[5].name, 'f')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_swap(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'swap "1" "4"')
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[1].name, 'e')
|
||||
self.assertEqual(self.b.current_playlist.tracks[2].name, 'c')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'd')
|
||||
self.assertEqual(self.b.current_playlist.tracks[4].name, 'b')
|
||||
self.assertEqual(self.b.current_playlist.tracks[5].name, 'f')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_swapid(self):
|
||||
self.b.current_playlist.load([
|
||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||
])
|
||||
result = self.h.handle_request(u'swapid "2" "5"')
|
||||
self.assertEqual(self.b.current_playlist.tracks[0].name, 'a')
|
||||
self.assertEqual(self.b.current_playlist.tracks[1].name, 'e')
|
||||
self.assertEqual(self.b.current_playlist.tracks[2].name, 'c')
|
||||
self.assertEqual(self.b.current_playlist.tracks[3].name, 'd')
|
||||
self.assertEqual(self.b.current_playlist.tracks[4].name, 'b')
|
||||
self.assertEqual(self.b.current_playlist.tracks[5].name, 'f')
|
||||
self.assert_(u'OK' in result)
|
||||
File diff suppressed because it is too large
Load Diff
168
tests/mpd/music_db_test.py
Normal file
168
tests/mpd/music_db_test.py
Normal file
@ -0,0 +1,168 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class MusicDatabaseHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_count(self):
|
||||
result = self.h.handle_request(u'count "tag" "needle"')
|
||||
self.assert_(u'songs: 0' in result)
|
||||
self.assert_(u'playtime: 0' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_find_album(self):
|
||||
result = self.h.handle_request(u'find "album" "what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_find_album_without_quotes(self):
|
||||
result = self.h.handle_request(u'find album "what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_find_artist(self):
|
||||
result = self.h.handle_request(u'find "artist" "what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_find_artist_without_quotes(self):
|
||||
result = self.h.handle_request(u'find artist "what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_find_title(self):
|
||||
result = self.h.handle_request(u'find "title" "what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_find_title_without_quotes(self):
|
||||
result = self.h.handle_request(u'find title "what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_find_else_should_fail(self):
|
||||
result = self.h.handle_request(u'find "somethingelse" "what"')
|
||||
self.assertEqual(result[0], u'ACK [2@0] {find} incorrect arguments')
|
||||
|
||||
def test_find_album_and_artist(self):
|
||||
result = self.h.handle_request(u'find album "album_what" artist "artist_what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_findadd(self):
|
||||
result = self.h.handle_request(u'findadd "album" "what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_list_artist(self):
|
||||
result = self.h.handle_request(u'list "artist"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_list_artist_without_quotes(self):
|
||||
result = self.h.handle_request(u'list artist')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_list_artist_without_quotes_and_capitalized(self):
|
||||
result = self.h.handle_request(u'list Artist')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_list_artist_with_artist_should_fail(self):
|
||||
result = self.h.handle_request(u'list "artist" "anartist"')
|
||||
self.assertEqual(result[0], u'ACK [2@0] {list} incorrect arguments')
|
||||
|
||||
def test_list_album_without_artist(self):
|
||||
result = self.h.handle_request(u'list "album"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_list_album_with_artist(self):
|
||||
result = self.h.handle_request(u'list "album" "anartist"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_list_album_artist_with_artist_without_quotes(self):
|
||||
result = self.h.handle_request(u'list album artist "anartist"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_listall(self):
|
||||
result = self.h.handle_request(u'listall "file:///dev/urandom"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_listallinfo(self):
|
||||
result = self.h.handle_request(u'listallinfo "file:///dev/urandom"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_lsinfo_without_path_returns_same_as_listplaylists(self):
|
||||
lsinfo_result = self.h.handle_request(u'lsinfo')
|
||||
listplaylists_result = self.h.handle_request(u'listplaylists')
|
||||
self.assertEqual(lsinfo_result, listplaylists_result)
|
||||
|
||||
def test_lsinfo_with_empty_path_returns_same_as_listplaylists(self):
|
||||
lsinfo_result = self.h.handle_request(u'lsinfo ""')
|
||||
listplaylists_result = self.h.handle_request(u'listplaylists')
|
||||
self.assertEqual(lsinfo_result, listplaylists_result)
|
||||
|
||||
def test_lsinfo_for_root_returns_same_as_listplaylists(self):
|
||||
lsinfo_result = self.h.handle_request(u'lsinfo "/"')
|
||||
listplaylists_result = self.h.handle_request(u'listplaylists')
|
||||
self.assertEqual(lsinfo_result, listplaylists_result)
|
||||
|
||||
def test_search_album(self):
|
||||
result = self.h.handle_request(u'search "album" "analbum"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_album_without_quotes(self):
|
||||
result = self.h.handle_request(u'search album "analbum"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_artist(self):
|
||||
result = self.h.handle_request(u'search "artist" "anartist"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_artist_without_quotes(self):
|
||||
result = self.h.handle_request(u'search artist "anartist"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_filename(self):
|
||||
result = self.h.handle_request(u'search "filename" "afilename"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_filename_without_quotes(self):
|
||||
result = self.h.handle_request(u'search filename "afilename"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_title(self):
|
||||
result = self.h.handle_request(u'search "title" "atitle"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_title_without_quotes(self):
|
||||
result = self.h.handle_request(u'search title "atitle"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_any(self):
|
||||
result = self.h.handle_request(u'search "any" "anything"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_any_without_quotes(self):
|
||||
result = self.h.handle_request(u'search any "anything"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_search_else_should_fail(self):
|
||||
result = self.h.handle_request(u'search "sometype" "something"')
|
||||
self.assertEqual(result[0], u'ACK [2@0] {search} incorrect arguments')
|
||||
|
||||
def test_update_without_uri(self):
|
||||
result = self.h.handle_request(u'update')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assert_(u'updating_db: 0' in result)
|
||||
|
||||
def test_update_with_uri(self):
|
||||
result = self.h.handle_request(u'update "file:///dev/urandom"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assert_(u'updating_db: 0' in result)
|
||||
|
||||
def test_rescan_without_uri(self):
|
||||
result = self.h.handle_request(u'rescan')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assert_(u'updating_db: 0' in result)
|
||||
|
||||
def test_rescan_with_uri(self):
|
||||
result = self.h.handle_request(u'rescan "file:///dev/urandom"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assert_(u'updating_db: 0' in result)
|
||||
217
tests/mpd/playback_test.py
Normal file
217
tests/mpd/playback_test.py
Normal file
@ -0,0 +1,217 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.models import Track
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class PlaybackOptionsHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_consume_off(self):
|
||||
result = self.h.handle_request(u'consume "0"')
|
||||
self.assertFalse(self.b.playback.consume)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_consume_on(self):
|
||||
result = self.h.handle_request(u'consume "1"')
|
||||
self.assertTrue(self.b.playback.consume)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_crossfade(self):
|
||||
result = self.h.handle_request(u'crossfade "10"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_random_off(self):
|
||||
result = self.h.handle_request(u'random "0"')
|
||||
self.assertFalse(self.b.playback.random)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_random_on(self):
|
||||
result = self.h.handle_request(u'random "1"')
|
||||
self.assertTrue(self.b.playback.random)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_repeat_off(self):
|
||||
result = self.h.handle_request(u'repeat "0"')
|
||||
self.assertFalse(self.b.playback.repeat)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_repeat_on(self):
|
||||
result = self.h.handle_request(u'repeat "1"')
|
||||
self.assertTrue(self.b.playback.repeat)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_setvol_below_min(self):
|
||||
result = self.h.handle_request(u'setvol "-10"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(0, self.b.mixer.volume)
|
||||
|
||||
def test_setvol_min(self):
|
||||
result = self.h.handle_request(u'setvol "0"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(0, self.b.mixer.volume)
|
||||
|
||||
def test_setvol_middle(self):
|
||||
result = self.h.handle_request(u'setvol "50"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(50, self.b.mixer.volume)
|
||||
|
||||
def test_setvol_max(self):
|
||||
result = self.h.handle_request(u'setvol "100"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(100, self.b.mixer.volume)
|
||||
|
||||
def test_setvol_above_max(self):
|
||||
result = self.h.handle_request(u'setvol "110"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(100, self.b.mixer.volume)
|
||||
|
||||
def test_setvol_plus_is_ignored(self):
|
||||
result = self.h.handle_request(u'setvol "+10"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(10, self.b.mixer.volume)
|
||||
|
||||
def test_single_off(self):
|
||||
result = self.h.handle_request(u'single "0"')
|
||||
self.assertFalse(self.b.playback.single)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_single_on(self):
|
||||
result = self.h.handle_request(u'single "1"')
|
||||
self.assertTrue(self.b.playback.single)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_replay_gain_mode_off(self):
|
||||
result = self.h.handle_request(u'replay_gain_mode "off"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_replay_gain_mode_track(self):
|
||||
result = self.h.handle_request(u'replay_gain_mode "track"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_replay_gain_mode_album(self):
|
||||
result = self.h.handle_request(u'replay_gain_mode "album"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_replay_gain_status_default(self):
|
||||
expected = u'off'
|
||||
result = self.h.handle_request(u'replay_gain_status')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assert_(expected in result)
|
||||
|
||||
#def test_replay_gain_status_off(self):
|
||||
# expected = u'off'
|
||||
# self.h._replay_gain_mode(expected)
|
||||
# result = self.h.handle_request(u'replay_gain_status')
|
||||
# self.assert_(u'OK' in result)
|
||||
# self.assert_(expected in result)
|
||||
|
||||
#def test_replay_gain_status_track(self):
|
||||
# expected = u'track'
|
||||
# self.h._replay_gain_mode(expected)
|
||||
# result = self.h.handle_request(u'replay_gain_status')
|
||||
# self.assert_(u'OK' in result)
|
||||
# self.assert_(expected in result)
|
||||
|
||||
#def test_replay_gain_status_album(self):
|
||||
# expected = u'album'
|
||||
# self.h._replay_gain_mode(expected)
|
||||
# result = self.h.handle_request(u'replay_gain_status')
|
||||
# self.assert_(u'OK' in result)
|
||||
# self.assert_(expected in result)
|
||||
|
||||
|
||||
class PlaybackControlHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_next(self):
|
||||
result = self.h.handle_request(u'next')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_pause_off(self):
|
||||
track = Track()
|
||||
self.b.current_playlist.load([track])
|
||||
self.h.handle_request(u'play "0"')
|
||||
self.h.handle_request(u'pause "1"')
|
||||
result = self.h.handle_request(u'pause "0"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
|
||||
|
||||
def test_pause_on(self):
|
||||
track = Track()
|
||||
self.b.current_playlist.load([track])
|
||||
self.h.handle_request(u'play "0"')
|
||||
result = self.h.handle_request(u'pause "1"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.PAUSED, self.b.playback.state)
|
||||
|
||||
def test_play_without_pos(self):
|
||||
track = Track()
|
||||
self.b.current_playlist.load([track])
|
||||
self.b.playback.state = self.b.playback.PAUSED
|
||||
result = self.h.handle_request(u'play')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
|
||||
|
||||
def test_play_with_pos(self):
|
||||
self.b.current_playlist.load([Track()])
|
||||
result = self.h.handle_request(u'play "0"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
|
||||
|
||||
def test_play_with_pos_out_of_bounds(self):
|
||||
self.b.current_playlist.load([])
|
||||
result = self.h.handle_request(u'play "0"')
|
||||
self.assertEqual(result[0], u'ACK [2@0] {play} Bad song index')
|
||||
self.assertEqual(self.b.playback.STOPPED, self.b.playback.state)
|
||||
|
||||
def test_play_minus_one_plays_first_in_playlist(self):
|
||||
track = Track()
|
||||
self.b.current_playlist.load([track])
|
||||
result = self.h.handle_request(u'play "-1"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
|
||||
self.assertEqual(self.b.playback.current_track, track)
|
||||
|
||||
def test_playid(self):
|
||||
self.b.current_playlist.load([Track()])
|
||||
result = self.h.handle_request(u'playid "1"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
|
||||
|
||||
def test_playid_minus_one_plays_first_in_playlist(self):
|
||||
track = Track()
|
||||
self.b.current_playlist.load([track])
|
||||
result = self.h.handle_request(u'playid "-1"')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
|
||||
self.assertEqual(self.b.playback.current_track, track)
|
||||
|
||||
def test_playid_which_does_not_exist(self):
|
||||
self.b.current_playlist.load([Track()])
|
||||
result = self.h.handle_request(u'playid "12345"')
|
||||
self.assertEqual(result[0], u'ACK [50@0] {playid} No such song')
|
||||
|
||||
def test_previous(self):
|
||||
result = self.h.handle_request(u'previous')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_seek(self):
|
||||
result = self.h.handle_request(u'seek "0" "30"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_seekid(self):
|
||||
result = self.h.handle_request(u'seekid "0" "30"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_stop(self):
|
||||
result = self.h.handle_request(u'stop')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assertEqual(self.b.playback.STOPPED, self.b.playback.state)
|
||||
44
tests/mpd/reflection_test.py
Normal file
44
tests/mpd/reflection_test.py
Normal file
@ -0,0 +1,44 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class ReflectionHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_commands_returns_list_of_all_commands(self):
|
||||
result = self.h.handle_request(u'commands')
|
||||
# Check if some random commands are included
|
||||
self.assert_(u'command: commands' in result)
|
||||
self.assert_(u'command: play' in result)
|
||||
self.assert_(u'command: status' in result)
|
||||
# Check if the blacklisted commands are not present
|
||||
self.assert_(u'command: command_list_begin' not in result)
|
||||
self.assert_(u'command: command_list_ok_begin' not in result)
|
||||
self.assert_(u'command: command_list_end' not in result)
|
||||
self.assert_(u'command: idle' not in result)
|
||||
self.assert_(u'command: noidle' not in result)
|
||||
self.assert_(u'command: sticker' not in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_decoders(self):
|
||||
result = self.h.handle_request(u'decoders')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_notcommands_returns_only_ok(self):
|
||||
result = self.h.handle_request(u'notcommands')
|
||||
self.assertEqual(1, len(result))
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_tagtypes(self):
|
||||
result = self.h.handle_request(u'tagtypes')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_urlhandlers(self):
|
||||
result = self.h.handle_request(u'urlhandlers')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assert_(u'handler: dummy:' in result)
|
||||
48
tests/mpd/request_handler_test.py
Normal file
48
tests/mpd/request_handler_test.py
Normal file
@ -0,0 +1,48 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.mpd import frontend, MpdAckError
|
||||
|
||||
class RequestHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_register_same_pattern_twice_fails(self):
|
||||
func = lambda: None
|
||||
try:
|
||||
frontend.handle_pattern('a pattern')(func)
|
||||
frontend.handle_pattern('a pattern')(func)
|
||||
self.fail('Registering a pattern twice shoulde raise ValueError')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_finding_handler_for_unknown_command_raises_exception(self):
|
||||
try:
|
||||
self.h.find_handler('an_unknown_command with args')
|
||||
self.fail('Should raise exception')
|
||||
except MpdAckError as e:
|
||||
self.assertEqual(e.get_mpd_ack(),
|
||||
u'ACK [5@0] {} unknown command "an_unknown_command"')
|
||||
|
||||
def test_finding_handler_for_known_command_returns_handler_and_kwargs(self):
|
||||
expected_handler = lambda x: None
|
||||
frontend._request_handlers['known_command (?P<arg1>.+)'] = \
|
||||
expected_handler
|
||||
(handler, kwargs) = self.h.find_handler('known_command an_arg')
|
||||
self.assertEqual(handler, expected_handler)
|
||||
self.assert_('arg1' in kwargs)
|
||||
self.assertEqual(kwargs['arg1'], 'an_arg')
|
||||
|
||||
def test_handling_unknown_request_yields_error(self):
|
||||
result = self.h.handle_request('an unhandled request')
|
||||
self.assertEqual(result[0], u'ACK [5@0] {} unknown command "an"')
|
||||
|
||||
def test_handling_known_request(self):
|
||||
expected = 'magic'
|
||||
frontend._request_handlers['known request'] = lambda x: expected
|
||||
result = self.h.handle_request('known request')
|
||||
self.assert_(u'OK' in result)
|
||||
self.assert_(expected in result)
|
||||
204
tests/mpd/status_test.py
Normal file
204
tests/mpd/status_test.py
Normal file
@ -0,0 +1,204 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.models import Track
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class StatusHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_clearerror(self):
|
||||
result = self.h.handle_request(u'clearerror')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_currentsong(self):
|
||||
track = Track()
|
||||
self.b.current_playlist.load([track])
|
||||
self.b.playback.play()
|
||||
result = self.h.handle_request(u'currentsong')
|
||||
self.assert_(u'file: ' in result)
|
||||
self.assert_(u'Time: 0' in result)
|
||||
self.assert_(u'Artist: ' in result)
|
||||
self.assert_(u'Title: ' in result)
|
||||
self.assert_(u'Album: ' in result)
|
||||
self.assert_(u'Track: 0' in result)
|
||||
self.assert_(u'Date: ' in result)
|
||||
self.assert_(u'Pos: 0' in result)
|
||||
self.assert_(u'Id: 1' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_currentsong_without_song(self):
|
||||
result = self.h.handle_request(u'currentsong')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_idle_without_subsystems(self):
|
||||
result = self.h.handle_request(u'idle')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_idle_with_subsystems(self):
|
||||
result = self.h.handle_request(u'idle database playlist')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_noidle(self):
|
||||
result = self.h.handle_request(u'noidle')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_stats_command(self):
|
||||
result = self.h.handle_request(u'stats')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_stats_method(self):
|
||||
result = self.h._status_stats()
|
||||
self.assert_('artists' in result)
|
||||
self.assert_(int(result['artists']) >= 0)
|
||||
self.assert_('albums' in result)
|
||||
self.assert_(int(result['albums']) >= 0)
|
||||
self.assert_('songs' in result)
|
||||
self.assert_(int(result['songs']) >= 0)
|
||||
self.assert_('uptime' in result)
|
||||
self.assert_(int(result['uptime']) >= 0)
|
||||
self.assert_('db_playtime' in result)
|
||||
self.assert_(int(result['db_playtime']) >= 0)
|
||||
self.assert_('db_update' in result)
|
||||
self.assert_(int(result['db_update']) >= 0)
|
||||
self.assert_('playtime' in result)
|
||||
self.assert_(int(result['playtime']) >= 0)
|
||||
|
||||
def test_status_command(self):
|
||||
result = self.h.handle_request(u'status')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_status_method_contains_volume_which_defaults_to_0(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('volume' in result)
|
||||
self.assertEqual(int(result['volume']), 0)
|
||||
|
||||
def test_status_method_contains_volume(self):
|
||||
self.b.mixer.volume = 17
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('volume' in result)
|
||||
self.assertEqual(int(result['volume']), 17)
|
||||
|
||||
def test_status_method_contains_repeat_is_0(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('repeat' in result)
|
||||
self.assertEqual(int(result['repeat']), 0)
|
||||
|
||||
def test_status_method_contains_repeat_is_1(self):
|
||||
self.b.playback.repeat = 1
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('repeat' in result)
|
||||
self.assertEqual(int(result['repeat']), 1)
|
||||
|
||||
def test_status_method_contains_random_is_0(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('random' in result)
|
||||
self.assertEqual(int(result['random']), 0)
|
||||
|
||||
def test_status_method_contains_random_is_1(self):
|
||||
self.b.playback.random = 1
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('random' in result)
|
||||
self.assertEqual(int(result['random']), 1)
|
||||
|
||||
def test_status_method_contains_single(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('single' in result)
|
||||
self.assert_(int(result['single']) in (0, 1))
|
||||
|
||||
def test_status_method_contains_consume_is_0(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('consume' in result)
|
||||
self.assertEqual(int(result['consume']), 0)
|
||||
|
||||
def test_status_method_contains_consume_is_1(self):
|
||||
self.b.playback.consume = 1
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('consume' in result)
|
||||
self.assertEqual(int(result['consume']), 1)
|
||||
|
||||
def test_status_method_contains_playlist(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('playlist' in result)
|
||||
self.assert_(int(result['playlist']) in xrange(0, 2**31 - 1))
|
||||
|
||||
def test_status_method_contains_playlistlength(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('playlistlength' in result)
|
||||
self.assert_(int(result['playlistlength']) >= 0)
|
||||
|
||||
def test_status_method_contains_xfade(self):
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('xfade' in result)
|
||||
self.assert_(int(result['xfade']) >= 0)
|
||||
|
||||
def test_status_method_contains_state_is_play(self):
|
||||
self.b.playback.state = self.b.playback.PLAYING
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('state' in result)
|
||||
self.assertEqual(result['state'], 'play')
|
||||
|
||||
def test_status_method_contains_state_is_stop(self):
|
||||
self.b.playback.state = self.b.playback.STOPPED
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('state' in result)
|
||||
self.assertEqual(result['state'], 'stop')
|
||||
|
||||
def test_status_method_contains_state_is_pause(self):
|
||||
self.b.playback.state = self.b.playback.PLAYING
|
||||
self.b.playback.state = self.b.playback.PAUSED
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('state' in result)
|
||||
self.assertEqual(result['state'], 'pause')
|
||||
|
||||
def test_status_method_when_playlist_loaded_contains_song(self):
|
||||
self.b.current_playlist.load([Track()])
|
||||
self.b.playback.play()
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('song' in result)
|
||||
self.assert_(int(result['song']) >= 0)
|
||||
|
||||
def test_status_method_when_playlist_loaded_contains_cpid_as_songid(self):
|
||||
self.b.current_playlist.load([Track()])
|
||||
self.b.playback.play()
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('songid' in result)
|
||||
self.assertEqual(int(result['songid']), 1)
|
||||
|
||||
def test_status_method_when_playing_contains_time_with_no_length(self):
|
||||
self.b.current_playlist.load([Track(length=None)])
|
||||
self.b.playback.play()
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('time' in result)
|
||||
(position, total) = result['time'].split(':')
|
||||
position = int(position)
|
||||
total = int(total)
|
||||
self.assert_(position <= total)
|
||||
|
||||
def test_status_method_when_playing_contains_time_with_length(self):
|
||||
self.b.current_playlist.load([Track(length=10000)])
|
||||
self.b.playback.play()
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('time' in result)
|
||||
(position, total) = result['time'].split(':')
|
||||
position = int(position)
|
||||
total = int(total)
|
||||
self.assert_(position <= total)
|
||||
|
||||
def test_status_method_when_playing_contains_elapsed(self):
|
||||
self.b.playback.state = self.b.playback.PAUSED
|
||||
self.b.playback._play_time_accumulated = 59123
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('elapsed' in result)
|
||||
self.assertEqual(int(result['elapsed']), 59123)
|
||||
|
||||
def test_status_method_when_playing_contains_bitrate(self):
|
||||
self.b.current_playlist.load([Track(bitrate=320)])
|
||||
self.b.playback.play()
|
||||
result = dict(self.h._status_status())
|
||||
self.assert_('bitrate' in result)
|
||||
self.assertEqual(int(result['bitrate']), 320)
|
||||
41
tests/mpd/stickers_test.py
Normal file
41
tests/mpd/stickers_test.py
Normal file
@ -0,0 +1,41 @@
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
class StickersHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_sticker_get(self):
|
||||
result = self.h.handle_request(
|
||||
u'sticker get "song" "file:///dev/urandom" "a_name"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_sticker_set(self):
|
||||
result = self.h.handle_request(
|
||||
u'sticker set "song" "file:///dev/urandom" "a_name" "a_value"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_sticker_delete_with_name(self):
|
||||
result = self.h.handle_request(
|
||||
u'sticker delete "song" "file:///dev/urandom" "a_name"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_sticker_delete_without_name(self):
|
||||
result = self.h.handle_request(
|
||||
u'sticker delete "song" "file:///dev/urandom"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_sticker_list(self):
|
||||
result = self.h.handle_request(
|
||||
u'sticker list "song" "file:///dev/urandom"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_sticker_find(self):
|
||||
result = self.h.handle_request(
|
||||
u'sticker find "song" "file:///dev/urandom" "a_name"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
87
tests/mpd/stored_playlists_test.py
Normal file
87
tests/mpd/stored_playlists_test.py
Normal file
@ -0,0 +1,87 @@
|
||||
import datetime as dt
|
||||
import unittest
|
||||
|
||||
from mopidy.backends.dummy import DummyBackend
|
||||
from mopidy.mixers.dummy import DummyMixer
|
||||
from mopidy.models import Track, Playlist
|
||||
from mopidy.mpd import frontend
|
||||
|
||||
from tests import SkipTest
|
||||
|
||||
class StoredPlaylistsHandlerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.m = DummyMixer()
|
||||
self.b = DummyBackend(mixer=self.m)
|
||||
self.h = frontend.MpdFrontend(backend=self.b)
|
||||
|
||||
def test_listplaylist(self):
|
||||
self.b.stored_playlists.playlists = [
|
||||
Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])]
|
||||
result = self.h.handle_request(u'listplaylist "name"')
|
||||
self.assert_(u'file: file:///dev/urandom' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_listplaylist_fails_if_no_playlist_is_found(self):
|
||||
result = self.h.handle_request(u'listplaylist "name"')
|
||||
self.assertEqual(result[0],
|
||||
u'ACK [50@0] {listplaylist} No such playlist')
|
||||
|
||||
def test_listplaylistinfo(self):
|
||||
self.b.stored_playlists.playlists = [
|
||||
Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])]
|
||||
result = self.h.handle_request(u'listplaylistinfo "name"')
|
||||
self.assert_(u'file: file:///dev/urandom' in result)
|
||||
self.assert_(u'Track: 0' in result)
|
||||
self.assert_(u'Pos: 0' not in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_listplaylistinfo_fails_if_no_playlist_is_found(self):
|
||||
result = self.h.handle_request(u'listplaylistinfo "name"')
|
||||
self.assertEqual(result[0],
|
||||
u'ACK [50@0] {listplaylistinfo} No such playlist')
|
||||
|
||||
def test_listplaylists(self):
|
||||
last_modified = dt.datetime(2001, 3, 17, 13, 41, 17, 12345)
|
||||
self.b.stored_playlists.playlists = [Playlist(name='a',
|
||||
last_modified=last_modified)]
|
||||
result = self.h.handle_request(u'listplaylists')
|
||||
self.assert_(u'playlist: a' in result)
|
||||
# Date without microseconds and with time zone information
|
||||
self.assert_(u'Last-Modified: 2001-03-17T13:41:17Z' in result)
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_load(self):
|
||||
result = self.h.handle_request(u'load "name"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_load_appends(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_playlistadd(self):
|
||||
result = self.h.handle_request(
|
||||
u'playlistadd "name" "file:///dev/urandom"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_playlistclear(self):
|
||||
result = self.h.handle_request(u'playlistclear "name"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_playlistdelete(self):
|
||||
result = self.h.handle_request(u'playlistdelete "name" "5"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_playlistmove(self):
|
||||
result = self.h.handle_request(u'playlistmove "name" "5" "10"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_rename(self):
|
||||
result = self.h.handle_request(u'rename "old_name" "new_name"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_rm(self):
|
||||
result = self.h.handle_request(u'rm "name"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
|
||||
def test_save(self):
|
||||
result = self.h.handle_request(u'save "name"')
|
||||
self.assert_(u'ACK [0@0] {} Not implemented' in result)
|
||||
@ -5,7 +5,6 @@ import sys
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
import urllib
|
||||
|
||||
from mopidy.utils import *
|
||||
from mopidy.models import Track, Artist, Album
|
||||
|
||||
Loading…
Reference in New Issue
Block a user