Merge commit 'adamcik/gstreamer'

This commit is contained in:
Stein Magnus Jodal 2010-04-29 21:27:06 +02:00
commit e84fe6ddd7
15 changed files with 669 additions and 54 deletions

View File

@ -176,7 +176,8 @@ class BaseCurrentPlaylistController(object):
assert start >= 0, 'start must be at least zero'
assert end <= len(tracks), 'end can not be larger than playlist length'
assert to_position >= 0, 'to_position must be at least zero'
assert to_position <= len(tracks), 'to_position can not be larger than playlist length'
assert to_position <= len(tracks), 'to_position can not be larger ' + \
'than playlist length'
new_tracks = tracks[:start] + tracks[end:]
for track in tracks[start:end]:
@ -218,7 +219,8 @@ class BaseCurrentPlaylistController(object):
assert start >= 0, 'start must be at least zero'
if end is not None:
assert end <= len(tracks), 'end can not be larger than playlist length'
assert end <= len(tracks), 'end can not be larger than ' + \
'playlist length'
before = tracks[:start or 0]
shuffled = tracks[start:end]

View File

@ -16,7 +16,7 @@ import threading
from mopidy.backends import *
from mopidy.models import Playlist, Track
from mopidy import settings
from mopidy.utils import m3u_to_uris
from mopidy.utils import parse_m3u
logger = logging.getLogger(u'backends.gstreamer')
@ -41,7 +41,7 @@ class GStreamerBackend(BaseBackend):
self.playback = GStreamerPlaybackController(self)
self.stored_playlists = GStreamerStoredPlaylistsController(self)
self.current_playlist = BaseCurrentPlaylistController(self)
self.uri_handlers = [u'file:']
self.uri_handlers = [u'file://']
class GStreamerPlaybackController(BasePlaybackController):
@ -127,11 +127,12 @@ class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController):
for m3u in glob.glob(os.path.join(self._folder, '*.m3u')):
name = os.path.basename(m3u)[:len('.m3u')]
track_uris = m3u_to_uris(m3u)
track_uris = parse_m3u(m3u)
tracks = map(lambda u: Track(uri=u), track_uris)
playlist = Playlist(tracks=tracks, name=name)
# FIXME playlist name needs better handling
# FIXME tracks should come from lib. lookup
playlists.append(playlist)
@ -170,8 +171,8 @@ class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController):
with open(file_path, 'w') as file:
for track in playlist.tracks:
if track.uri.startswith('file:'):
file.write(track.uri[len('file:'):] + '\n')
if track.uri.startswith('file://'):
file.write(track.uri[len('file://'):] + '\n')
else:
file.write(track.uri + '\n')

View File

@ -37,7 +37,7 @@ class DenonMixer(BaseMixer):
self._lock = Lock()
def _get_volume(self):
self._lock.acquire();
self._lock.acquire()
self.ensure_open_device()
self._device.write('MV?\r')
vol = str(self._device.readline()[2:4])

View File

@ -17,7 +17,7 @@ class OsaMixer(BaseMixer):
and (int(time.time() - self._last_update) < self.CACHE_TTL))
def _get_volume(self):
if not self._valid_cache():
if not self._valid_cache():
try:
self._cache = int(Popen(
['osascript', '-e',

View File

@ -10,13 +10,32 @@ class ImmutableObject(object):
"""
def __init__(self, *args, **kwargs):
self.__dict__.update(kwargs)
for key, value in kwargs.items():
if not hasattr(self, key):
raise TypeError('__init__() got an unexpected keyword ' + \
'argument \'%s\'' % key)
self.__dict__[key] = value
def __setattr__(self, name, value):
if name.startswith('_'):
return super(ImmutableObject, self).__setattr__(name, value)
raise AttributeError('Object is immutable.')
def __hash__(self):
hash_sum = 0
for key, value in self.__dict__.items():
hash_sum += hash(key) + hash(value)
return hash_sum
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
return self.__dict__ == other.__dict__
def __ne__(self, other):
return not self.__eq__(other)
class Artist(ImmutableObject):
"""
@ -55,13 +74,13 @@ class Album(ImmutableObject):
num_tracks = 0
def __init__(self, *args, **kwargs):
self._artists = kwargs.pop('artists', [])
self._artists = frozenset(kwargs.pop('artists', []))
super(Album, self).__init__(*args, **kwargs)
@property
def artists(self):
"""List of :class:`Artist` elements. Read-only."""
return copy(self._artists)
return list(self._artists)
class Track(ImmutableObject):
@ -111,13 +130,13 @@ class Track(ImmutableObject):
id = None
def __init__(self, *args, **kwargs):
self._artists = kwargs.pop('artists', [])
self._artists = frozenset(kwargs.pop('artists', []))
super(Track, self).__init__(*args, **kwargs)
@property
def artists(self):
"""List of :class:`Artist`. Read-only."""
return copy(self._artists)
return list(self._artists)
def mpd_format(self, position=0, search_result=False):
"""
@ -151,7 +170,9 @@ class Track(ImmutableObject):
:rtype: string
"""
return u', '.join([a.name for a in self.artists])
artists = list(self._artists)
artists.sort(key=lambda a: a.name)
return u', '.join([a.name for a in artists])
class Playlist(ImmutableObject):

View File

@ -643,7 +643,7 @@ class MpdFrontend(object):
- capitalizes the type argument.
"""
type = type.lower()
pass # TODO
# TODO
@handle_pattern(r'^listall "(?P<uri>[^"]+)"')
def _music_db_listall(self, uri):

View File

@ -26,7 +26,8 @@ BACKENDS = (
#: The log format used on the console. See
#: http://docs.python.org/library/logging.html#formatter-objects for details on
#: the format.
CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s [%(process)d:%(threadName)s] %(name)s\n %(message)s'
CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s' + \
' [%(process)d:%(threadName)s] %(name)s\n %(message)s'
#: Protocol frontend to use. Default::
#:
@ -104,6 +105,12 @@ SPOTIFY_LIB_CACHE = u'~/.mopidy/libspotify_cache'
#: Path to playlist folder with m3u files.
PLAYLIST_FOLDER = u'~/.mopidy/playlists'
#: Path to folder with local music.
MUSIC_FOLDER = u'~/music'
#: Path to MPD tag_cache for local music
TAG_CACHE = u'~/.mopidy/tag_cache'
# Import user specific settings
dotdir = os.path.expanduser(u'~/.mopidy/')
settings_file = os.path.join(dotdir, u'settings.py')

View File

@ -6,6 +6,8 @@ import urllib
logger = logging.getLogger('mopidy.utils')
from mopidy.models import Track, Artist, Album
def flatten(the_list):
result = []
for element in the_list:
@ -93,7 +95,7 @@ def spotify_uri_to_int(uri, output_bits=31):
full_id >>= output_bits
return int(compressed_id)
def m3u_to_uris(file_path):
def parse_m3u(file_path):
"""
Convert M3U file list of uris
@ -124,11 +126,71 @@ def m3u_to_uris(file_path):
if line.startswith('#'):
continue
if line.startswith('file:'):
# FIXME what about other URI types?
if line.startswith('file://'):
uris.append(line)
else:
file = os.path.join(folder, line)
path = urllib.pathname2url(file.encode('utf-8'))
uris.append('file:' + path)
path = os.path.join(folder, line)
path = urllib.pathname2url(path.encode('utf-8'))
uris.append('file://' + path)
return uris
def parse_mpd_tag_cache(tag_cache, music_dir=''):
"""
Converts a MPD tag_cache into a lists of tracks, artists and albums.
"""
with open(tag_cache) as library:
contents = library.read()
tracks = set()
artists = set()
albums = set()
current = {}
state = None
for line in contents.split('\n'):
if line == 'songList begin':
state = 'songs'
continue
elif line == 'songList end':
state = None
continue
elif not state:
continue
key, value = line.split(': ', 1)
if key == 'key':
_convert_mpd_data(current, tracks, artists, albums, music_dir)
current.clear()
current[key.lower()] = value
_convert_mpd_data(current, tracks, artists, albums, music_dir)
return tracks, artists, albums
def _convert_mpd_data(data, tracks, artists, albums, music_dir):
if not data:
return
num_tracks = int(data['track'].split('/')[1])
track_no = int(data['track'].split('/')[0])
path = data['file']
if path[0] == '/':
path = path[1:]
path = os.path.join(music_dir, path)
uri = 'file://' + urllib.pathname2url(path)
artist = Artist(name=data['artist'])
artists.add(artist)
album = Album(name=data['album'], artists=[artist], num_tracks=num_tracks)
albums.add(album)
track = Track(name=data['title'], artists=[artist], track_no=track_no,
length=int(data['time'])*1000, uri=uri, album=album)
tracks.add(track)

View File

@ -13,7 +13,8 @@ from tests import SkipTest
__all__ = ['BaseCurrentPlaylistControllerTest',
'BasePlaybackControllerTest',
'BaseStoredPlaylistsControllerTest']
'BaseStoredPlaylistsControllerTest',
'BaseLibraryControllerTest']
def populate_playlist(func):
def wrapper(self):
@ -96,7 +97,7 @@ class BaseCurrentPlaylistControllerTest(object):
def test_load(self):
new_playlist = Playlist()
self.assertNotEqual(new_playlist, self.controller.playlist)
self.assertNotEqual(id(new_playlist), id(self.controller.playlist))
self.controller.load(new_playlist)
# FIXME how do we test this without going into internals?
self.assertEqual(new_playlist, self.controller._playlist)
@ -175,7 +176,7 @@ class BaseCurrentPlaylistControllerTest(object):
playlist1 = self.controller.playlist
playlist2 = self.controller.playlist
self.assertNotEqual(playlist1, playlist2)
self.assertNotEqual(id(playlist1), id(playlist2))
@populate_playlist
def test_remove(self):
@ -965,9 +966,59 @@ class BaseStoredPlaylistsControllerTest(object):
def test_rename_unknown_playlist(self):
self.stored.rename(Playlist(), 'test2')
test = lambda: self.stored.get(name='test2')
self.assertRaises(LookupError, test)
def test_save(self):
# FIXME should we handle playlists without names?
playlist = Playlist(name='test')
self.stored.save(playlist)
self.assert_(playlist in self.stored.playlists)
class BaseLibraryControllerTest(object):
def setUp(self):
self.backend = self.backend_class(mixer=DummyMixer())
self.controller = self.backend.library
def tearDown(self):
self.backend.destroy()
def test_refresh(self):
raise SkipTest
def test_lookup(self):
raise SkipTest
def test_lookup_unknown_track(self):
raise SkipTest
def test_find_exact_no_hits(self):
raise SkipTest
def test_find_exact_artist(self):
raise SkipTest
def test_find_exact_track(self):
raise SkipTest
def test_find_exact_album(self):
raise SkipTest
def test_find_search_no_hits(self):
raise SkipTest
def test_find_search_artist(self):
raise SkipTest
def test_find_search_track(self):
raise SkipTest
def test_find_search_album(self):
raise SkipTest
def test_find_search_uri(self):
raise SkipTest
def test_find_search_any(self):
raise SkipTest

View File

@ -14,7 +14,7 @@ folder = os.path.dirname(__file__)
folder = os.path.join(folder, '..', 'data')
folder = os.path.abspath(folder)
song = os.path.join(folder, 'song%s.wav')
generate_song = lambda i: 'file:' + urllib.pathname2url(song % i)
generate_song = lambda i: 'file://' + urllib.pathname2url(song % i)
# FIXME can be switched to generic test
class GStreamerCurrentPlaylistHandlerTest(BaseCurrentPlaylistControllerTest, unittest.TestCase):
@ -28,12 +28,12 @@ class GStreamerPlaybackControllerTest(BasePlaybackControllerTest, unittest.TestC
backend_class = GStreamerBackend
def add_track(self, file):
uri = 'file:' + urllib.pathname2url(os.path.join(folder, file))
uri = 'file://' + urllib.pathname2url(os.path.join(folder, file))
track = Track(uri=uri, id=1, length=4464)
self.backend.current_playlist.add(track)
def test_uri_handler(self):
self.assert_('file:' in self.backend.uri_handlers)
self.assert_('file://' in self.backend.uri_handlers)
def test_play_mp3(self):
self.add_track('blank.mp3')
@ -57,14 +57,16 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
backend_class = GStreamerBackend
def test_created_playlist_is_persisted(self):
path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
self.assert_(not os.path.exists(path))
self.stored.create('test')
file = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
self.assert_(os.path.exists(file))
self.assert_(os.path.exists(path))
def test_saved_playlist_is_persisted(self):
path = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
self.assert_(not os.path.exists(path))
self.stored.save(Playlist(name='test2'))
file = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
self.assert_(os.path.exists(file))
self.assert_(os.path.exists(path))
def test_deleted_playlist_get_removed(self):
playlist = self.stored.create('test')
@ -74,15 +76,16 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
def test_renamed_playlist_gets_moved(self):
playlist = self.stored.create('test')
self.stored.rename(playlist, 'test2')
file1 = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
file2 = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
self.assert_(not os.path.exists(file2))
self.stored.rename(playlist, 'test2')
self.assert_(not os.path.exists(file1))
self.assert_(os.path.exists(file2))
def test_playlist_contents_get_written_to_disk(self):
track = Track(uri=generate_song(1))
uri = track.uri[len('file:'):]
uri = track.uri[len('file://'):]
playlist = Playlist(tracks=[track], name='test')
file_path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
@ -95,7 +98,7 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
def test_playlists_are_loaded_at_startup(self):
track = Track(uri=generate_song(1))
uri = track.uri[len('file:'):]
uri = track.uri[len('file://'):]
playlist = Playlist(tracks=[track], name='test')
file_path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
@ -121,5 +124,12 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
def test_save_sets_playlist_uri(self):
raise SkipTest
class GStreamerBackendLibraryControllerTest(BaseStoredPlaylistsControllerTest,
unittest.TestCase):
backend_class = GStreamerBackend
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,102 @@
info_begin
mpd_version: 0.14.2
fs_charset: UTF-8
info_end
directory: subdir1
begin: subdir1
directory: subsubdir
begin: subdir1/subsubdir
songList begin
key: song8.mp3
file: subdir1/subsubdir/song8.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
key: song9.mp3
file: subdir1/subsubdir/song9.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
songList end
end: subdir1/subsubdir
songList begin
key: song4.mp3
file: subdir1/song4.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
key: song5.mp3
file: subdir1/song5.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
songList end
end: subdir1
directory: subdir2
begin: subdir2
songList begin
key: song6.mp3
file: subdir2/song6.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
key: song7.mp3
file: subdir2/song7.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
songList end
end: subdir2
songList begin
key: song1.mp3
file: /song1.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
key: song2.mp3
file: /song2.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
key: song3.mp3
file: /song3.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
songList end

View File

@ -0,0 +1,6 @@
info_begin
mpd_version: 0.14.2
fs_charset: UTF-8
info_end
songList begin
songList end

View File

@ -0,0 +1,15 @@
info_begin
mpd_version: 0.14.2
fs_charset: UTF-8
info_end
songList begin
key: song1.mp3
file: /song1.mp3
Time: 4
Artist: name
Title: trackname
Album: albumname
Track: 1/2
Date: 2006
mtime: 1272319626
songList end

View File

@ -3,6 +3,8 @@ import unittest
from mopidy.models import Artist, Album, Track, Playlist
from tests import SkipTest
class ArtistTest(unittest.TestCase):
def test_uri(self):
uri = u'an_uri'
@ -16,6 +18,52 @@ class ArtistTest(unittest.TestCase):
self.assertEqual(artist.name, name)
self.assertRaises(AttributeError, setattr, artist, 'name', None)
def test_invalid_kwarg(self):
test = lambda: Artist(foo='baz')
self.assertRaises(TypeError, test)
def test_eq_name(self):
artist1 = Artist(name=u'name')
artist2 = Artist(name=u'name')
self.assertEqual(artist1, artist2)
self.assertEqual(hash(artist1), hash(artist2))
def test_eq_uri(self):
artist1 = Artist(uri=u'uri')
artist2 = Artist(uri=u'uri')
self.assertEqual(artist1, artist2)
self.assertEqual(hash(artist1), hash(artist2))
def test_eq(self):
artist1 = Artist(uri=u'uri', name=u'name')
artist2 = Artist(uri=u'uri', name=u'name')
self.assertEqual(artist1, artist2)
self.assertEqual(hash(artist1), hash(artist2))
def test_eq_none(self):
self.assertNotEqual(Artist(), None)
def test_eq_other(self):
self.assertNotEqual(Artist(), 'other')
def test_ne_name(self):
artist1 = Artist(name=u'name1')
artist2 = Artist(name=u'name2')
self.assertNotEqual(artist1, artist2)
self.assertNotEqual(hash(artist1), hash(artist2))
def test_ne_uri(self):
artist1 = Artist(uri=u'uri1')
artist2 = Artist(uri=u'uri2')
self.assertNotEqual(artist1, artist2)
self.assertNotEqual(hash(artist1), hash(artist2))
def test_ne(self):
artist1 = Artist(uri=u'uri1', name=u'name1')
artist2 = Artist(uri=u'uri2', name=u'name2')
self.assertNotEqual(artist1, artist2)
self.assertNotEqual(hash(artist1), hash(artist2))
class AlbumTest(unittest.TestCase):
def test_uri(self):
@ -42,6 +90,86 @@ class AlbumTest(unittest.TestCase):
self.assertEqual(album.num_tracks, num_tracks)
self.assertRaises(AttributeError, setattr, album, 'num_tracks', None)
def test_invalid_kwarg(self):
test = lambda: Album(foo='baz')
self.assertRaises(TypeError, test)
def test_eq_name(self):
album1 = Album(name=u'name')
album2 = Album(name=u'name')
self.assertEqual(album1, album2)
self.assertEqual(hash(album1), hash(album2))
def test_eq_uri(self):
album1 = Album(uri=u'uri')
album2 = Album(uri=u'uri')
self.assertEqual(album1, album2)
self.assertEqual(hash(album1), hash(album2))
def test_eq_artists(self):
artists = [Artist()]
album1 = Album(artists=artists)
album2 = Album(artists=artists)
self.assertEqual(album1, album2)
self.assertEqual(hash(album1), hash(album2))
def test_eq_artists_order(self):
artist1 = Artist(name=u'name1')
artist2 = Artist(name=u'name2')
album1 = Album(artists=[artist1, artist2])
album2 = Album(artists=[artist2, artist1])
self.assertEqual(album1, album2)
self.assertEqual(hash(album1), hash(album2))
def test_eq_num_tracks(self):
album1 = Album(num_tracks=2)
album2 = Album(num_tracks=2)
self.assertEqual(album1, album2)
self.assertEqual(hash(album1), hash(album2))
def test_eq(self):
artists = [Artist()]
album1 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2)
album2 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2)
self.assertEqual(album1, album2)
self.assertEqual(hash(album1), hash(album2))
def test_eq_none(self):
self.assertNotEqual(Album(), None)
def test_eq_other(self):
self.assertNotEqual(Album(), 'other')
def test_ne_name(self):
album1 = Album(name=u'name1')
album2 = Album(name=u'name2')
self.assertNotEqual(album1, album2)
self.assertNotEqual(hash(album1), hash(album2))
def test_ne_uri(self):
album1 = Album(uri=u'uri1')
album2 = Album(uri=u'uri2')
self.assertNotEqual(album1, album2)
self.assertNotEqual(hash(album1), hash(album2))
def test_ne_artists(self):
album1 = Album(artists=[Artist(name=u'name1')])
album2 = Album(artists=[Artist(name=u'name2')])
self.assertNotEqual(album1, album2)
self.assertNotEqual(hash(album1), hash(album2))
def test_ne_num_tracks(self):
album1 = Album(num_tracks=1)
album2 = Album(num_tracks=2)
self.assertNotEqual(album1, album2)
self.assertNotEqual(hash(album1), hash(album2))
def test_ne(self):
album1 = Album(name=u'name1', uri=u'uri1', artists=[Artist(name=u'name1')], num_tracks=1)
album2 = Album(name=u'name2', uri=u'uri2', artists=[Artist(name=u'name2')], num_tracks=2)
self.assertNotEqual(album1, album2)
self.assertNotEqual(hash(album1), hash(album2))
class TrackTest(unittest.TestCase):
def test_uri(self):
@ -57,9 +185,9 @@ class TrackTest(unittest.TestCase):
self.assertRaises(AttributeError, setattr, track, 'name', None)
def test_artists(self):
artists = [Artist(), Artist()]
artists = [Artist(name=u'name1'), Artist(name=u'name2')]
track = Track(artists=artists)
self.assertEqual(track.artists, artists)
self.assertEqual(set(track.artists), set(artists))
self.assertRaises(AttributeError, setattr, track, 'artists', None)
def test_album(self):
@ -137,6 +265,157 @@ class TrackTest(unittest.TestCase):
track = Track(artists=[Artist(name=u'ABBA'), Artist(name=u'Beatles')])
self.assertEqual(track.mpd_format_artists(), u'ABBA, Beatles')
def test_invalid_kwarg(self):
test = lambda: Track(foo='baz')
self.assertRaises(TypeError, test)
def test_eq_uri(self):
track1 = Track(uri=u'uri1')
track2 = Track(uri=u'uri1')
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_name(self):
track1 = Track(name=u'name1')
track2 = Track(name=u'name1')
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_artists(self):
artists = [Artist()]
track1 = Track(artists=artists)
track2 = Track(artists=artists)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_artists_order(self):
artist1 = Artist(name=u'name1')
artist2 = Artist(name=u'name2')
track1 = Track(artists=[artist1, artist2])
track2 = Track(artists=[artist2, artist1])
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_album(self):
album = Album()
track1 = Track(album=album)
track2 = Track(album=album)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_track_no(self):
track1 = Track(track_no=1)
track2 = Track(track_no=1)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_date(self):
date = dt.date.today()
track1 = Track(date=date)
track2 = Track(date=date)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_length(self):
track1 = Track(length=100)
track2 = Track(length=100)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_bitrate(self):
track1 = Track(bitrate=100)
track2 = Track(bitrate=100)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_id(self):
track1 = Track(id=100)
track2 = Track(id=100)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq(self):
date = dt.date.today()
artists = [Artist()]
album = Album()
track1 = Track(uri=u'uri', name=u'name', artists=artists, album=album,
track_no=1, date=date, length=100, bitrate=100, id=2)
track2 = Track(uri=u'uri', name=u'name', artists=artists, album=album,
track_no=1, date=date, length=100, bitrate=100, id=2)
self.assertEqual(track1, track2)
self.assertEqual(hash(track1), hash(track2))
def test_eq_none(self):
self.assertNotEqual(Track(), None)
def test_eq_other(self):
self.assertNotEqual(Track(), 'other')
def test_ne_uri(self):
track1 = Track(uri=u'uri1')
track2 = Track(uri=u'uri2')
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_name(self):
track1 = Track(name=u'name1')
track2 = Track(name=u'name2')
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_artists(self):
track1 = Track(artists=[Artist(name=u'name1')])
track2 = Track(artists=[Artist(name=u'name2')])
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_album(self):
track1 = Track(album=Album(name=u'name1'))
track2 = Track(album=Album(name=u'name2'))
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_track_no(self):
track1 = Track(track_no=1)
track2 = Track(track_no=2)
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_date(self):
track1 = Track(date=dt.date.today())
track2 = Track(date=dt.date.today()-dt.timedelta(days=1))
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_length(self):
track1 = Track(length=100)
track2 = Track(length=200)
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_bitrate(self):
track1 = Track(bitrate=100)
track2 = Track(bitrate=200)
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne_id(self):
track1 = Track(id=100)
track2 = Track(id=200)
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
def test_ne(self):
track1 = Track(uri=u'uri1', name=u'name1',
artists=[Artist(name=u'name1')], album=Album(name=u'name1'),
track_no=1, date=dt.date.today(), length=100, bitrate=100, id=2)
track2 = Track(uri=u'uri2', name=u'name2',
artists=[Artist(name=u'name2')], album=Album(name=u'name2'),
track_no=2, date=dt.date.today()-dt.timedelta(days=1),
length=200, bitrate=200, id=1)
self.assertNotEqual(track1, track2)
self.assertNotEqual(hash(track1), hash(track2))
class PlaylistTest(unittest.TestCase):
def test_uri(self):
@ -241,3 +520,11 @@ class PlaylistTest(unittest.TestCase):
self.assertEqual(new_playlist.name, u'a name')
self.assertEqual(new_playlist.tracks, tracks)
self.assertEqual(new_playlist.last_modified, new_last_modified)
def test_invalid_kwarg(self):
test = lambda: Playlist(foo='baz')
self.assertRaises(TypeError, test)
def test_eq(self):
# FIXME missing all equal and hash tests
raise SkipTest

View File

@ -5,7 +5,10 @@ import tempfile
import unittest
import urllib
from mopidy.utils import m3u_to_uris
from mopidy.utils import parse_m3u, parse_mpd_tag_cache
from mopidy.models import Track, Artist, Album
from tests import SkipTest
def data(name):
folder = os.path.dirname(__file__)
@ -17,31 +20,30 @@ def data(name):
song1_path = data('song1.mp3')
song2_path = data('song2.mp3')
encoded_path = data(u'æøå.mp3')
song1_uri = 'file:' + urllib.pathname2url(song1_path)
song2_uri = 'file:' + urllib.pathname2url(song2_path)
encoded_uri = 'file:' + urllib.pathname2url(encoded_path.encode('utf-8'))
song1_uri = 'file://' + urllib.pathname2url(song1_path)
song2_uri = 'file://' + urllib.pathname2url(song2_path)
encoded_uri = 'file://' + urllib.pathname2url(encoded_path.encode('utf-8'))
class M3UToUriTest(unittest.TestCase):
def test_empty_file(self):
uris = m3u_to_uris(data('empty.m3u'))
uris = parse_m3u(data('empty.m3u'))
self.assertEqual([], uris)
def test_basic_file(self):
uris = m3u_to_uris(data('one.m3u'))
uris = parse_m3u(data('one.m3u'))
self.assertEqual([song1_uri], uris)
def test_file_with_comment(self):
uris = m3u_to_uris(data('comment.m3u'))
uris = parse_m3u(data('comment.m3u'))
self.assertEqual([song1_uri], uris)
def test_file_with_absolute_files(self):
with tempfile.NamedTemporaryFile() as file:
file.write(song1_path)
file.flush()
uris = m3u_to_uris(file.name)
self.assertEqual([song1_uri], uris)
uris = parse_m3u(file.name)
self.assertEqual([song1_uri], uris)
def test_file_with_multiple_absolute_files(self):
with tempfile.NamedTemporaryFile() as file:
@ -49,18 +51,67 @@ class M3UToUriTest(unittest.TestCase):
file.write('# comment \n')
file.write(song2_path)
file.flush()
uris = m3u_to_uris(file.name)
self.assertEqual([song1_uri, song2_uri], uris)
uris = parse_m3u(file.name)
self.assertEqual([song1_uri, song2_uri], uris)
def test_file_with_uri(self):
with tempfile.NamedTemporaryFile() as file:
file.write(song1_uri)
file.flush()
uris = m3u_to_uris(file.name)
self.assertEqual([song1_uri], uris)
uris = parse_m3u(file.name)
self.assertEqual([song1_uri], uris)
def test_encoding_is_latin1(self):
uris = m3u_to_uris(data('encoding.m3u'))
uris = parse_m3u(data('encoding.m3u'))
self.assertEqual([encoded_uri], uris)
expected_artists = [Artist(name='name')]
expected_albums = [Album(name='albumname', artists=expected_artists, num_tracks=2)]
expected_tracks = []
def generate_track(path):
uri = 'file://' + urllib.pathname2url(data(path))
track = Track(name='trackname', artists=expected_artists, track_no=1,
album=expected_albums[0], length=4000, uri=uri)
expected_tracks.append(track)
generate_track('song1.mp3')
generate_track('song2.mp3')
generate_track('song3.mp3')
generate_track('subdir1/song4.mp3')
generate_track('subdir1/song5.mp3')
generate_track('subdir2/song6.mp3')
generate_track('subdir2/song7.mp3')
generate_track('subdir1/subsubdir/song8.mp3')
generate_track('subdir1/subsubdir/song9.mp3')
class MPDTagCacheToTracksTest(unittest.TestCase):
def test_emtpy_cache(self):
tracks, artists, albums = parse_mpd_tag_cache(data('empty_tag_cache'),
data(''))
self.assertEqual(set(), tracks)
self.assertEqual(set(), artists)
self.assertEqual(set(), albums)
def test_simple_cache(self):
tracks, artists, albums = parse_mpd_tag_cache(data('simple_tag_cache'),
data(''))
self.assertEqual(expected_tracks[0], list(tracks)[0])
self.assertEqual(set(expected_artists), artists)
self.assertEqual(set(expected_albums), albums)
def test_advanced_cache(self):
tracks, artists, albums = parse_mpd_tag_cache(data('advanced_tag_cache'),
data(''))
self.assertEqual(set(expected_tracks), tracks)
self.assertEqual(set(expected_artists), artists)
self.assertEqual(set(expected_albums), albums)
def test_unicode_cache(self):
raise SkipTest
def test_misencoded_cache(self):
# FIXME not sure if this can happen
raise SkipTest