from __future__ import unicode_literals import datetime import os import unittest from mopidy.utils.path import mtime, uri_to_path from mopidy.frontends.mpd import translator, protocol from mopidy.models import Album, Artist, TlTrack, Playlist, Track class TrackMpdFormatTest(unittest.TestCase): track = Track( uri='a uri', artists=[Artist(name='an artist')], name='a name', album=Album(name='an album', num_tracks=13, artists=[Artist(name='an other artist')]), track_no=7, composers=[Artist(name='a composer')], performers=[Artist(name='a performer')], genre='a genre', date=datetime.date(1977, 1, 1), disc_no='1', comment='a comment', length=137000, ) def setUp(self): self.media_dir = '/dir/subdir' mtime.set_fake_time(1234567) def tearDown(self): mtime.undo_fake() def test_track_to_mpd_format_for_empty_track(self): result = translator.track_to_mpd_format(Track()) self.assertIn(('file', ''), result) self.assertIn(('Time', 0), result) self.assertIn(('Artist', ''), result) self.assertIn(('Title', ''), result) self.assertIn(('Album', ''), result) self.assertIn(('Track', 0), result) self.assertEqual(len(result), 6) def test_track_to_mpd_format_with_position(self): result = translator.track_to_mpd_format(Track(), position=1) self.assertNotIn(('Pos', 1), result) def test_track_to_mpd_format_with_tlid(self): result = translator.track_to_mpd_format(TlTrack(1, Track())) self.assertNotIn(('Id', 1), result) def test_track_to_mpd_format_with_position_and_tlid(self): result = translator.track_to_mpd_format( TlTrack(2, Track()), position=1) self.assertIn(('Pos', 1), result) self.assertIn(('Id', 2), result) def test_track_to_mpd_format_for_nonempty_track(self): result = translator.track_to_mpd_format( TlTrack(122, self.track), position=9) self.assertIn(('file', 'a uri'), result) self.assertIn(('Time', 137), result) self.assertIn(('Artist', 'an artist'), result) self.assertIn(('Title', 'a name'), result) self.assertIn(('Album', 'an album'), result) self.assertIn(('AlbumArtist', 'an other artist'), result) self.assertIn(('Composer', 'a composer'), result) self.assertIn(('Performer', 'a performer'), result) self.assertIn(('Genre', 'a genre'), result) self.assertIn(('Track', '7/13'), result) self.assertIn(('Date', datetime.date(1977, 1, 1)), result) self.assertIn(('Disc', '1'), result) self.assertIn(('Comment', 'a comment'), result) self.assertIn(('Pos', 9), result) self.assertIn(('Id', 122), result) self.assertEqual(len(result), 15) def test_track_to_mpd_format_musicbrainz_trackid(self): track = self.track.copy(musicbrainz_id='foo') result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_TRACKID', 'foo'), result) def test_track_to_mpd_format_musicbrainz_albumid(self): album = self.track.album.copy(musicbrainz_id='foo') track = self.track.copy(album=album) result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_ALBUMID', 'foo'), result) def test_track_to_mpd_format_musicbrainz_albumartistid(self): artist = list(self.track.artists)[0].copy(musicbrainz_id='foo') album = self.track.album.copy(artists=[artist]) track = self.track.copy(album=album) result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_ALBUMARTISTID', 'foo'), result) def test_track_to_mpd_format_musicbrainz_artistid(self): artist = list(self.track.artists)[0].copy(musicbrainz_id='foo') track = self.track.copy(artists=[artist]) result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_ARTISTID', 'foo'), result) def test_artists_to_mpd_format(self): artists = [Artist(name='ABBA'), Artist(name='Beatles')] translated = translator.artists_to_mpd_format(artists) self.assertEqual(translated, 'ABBA, Beatles') def test_artists_to_mpd_format_artist_with_no_name(self): artists = [Artist(name=None)] translated = translator.artists_to_mpd_format(artists) self.assertEqual(translated, '') class PlaylistMpdFormatTest(unittest.TestCase): def test_mpd_format(self): playlist = Playlist(tracks=[ Track(track_no=1), Track(track_no=2), Track(track_no=3)]) result = translator.playlist_to_mpd_format(playlist) self.assertEqual(len(result), 3) def test_mpd_format_with_range(self): playlist = Playlist(tracks=[ Track(track_no=1), Track(track_no=2), Track(track_no=3)]) result = translator.playlist_to_mpd_format(playlist, 1, 2) self.assertEqual(len(result), 1) self.assertEqual(dict(result[0])['Track'], 2) class QueryFromMpdSearchFormatTest(unittest.TestCase): def test_dates_are_extracted(self): result = translator.query_from_mpd_search_format( 'Date "1974-01-02" Date "1975"') self.assertEqual(result['date'][0], '1974-01-02') self.assertEqual(result['date'][1], '1975') # TODO Test more mappings class QueryFromMpdListFormatTest(unittest.TestCase): pass # TODO class TracksToTagCacheFormatTest(unittest.TestCase): def setUp(self): self.media_dir = '/dir/subdir' mtime.set_fake_time(1234567) def tearDown(self): mtime.undo_fake() def translate(self, track): base_path = self.media_dir.encode('utf-8') result = dict(translator.track_to_mpd_format(track)) result['file'] = uri_to_path(result['file'])[len(base_path) + 1:] result['key'] = os.path.basename(result['file']) result['mtime'] = mtime('') return translator.order_mpd_track_info(result.items()) def consume_headers(self, result): self.assertEqual(('info_begin',), result[0]) self.assertEqual(('mpd_version', protocol.VERSION), result[1]) self.assertEqual(('fs_charset', protocol.ENCODING), result[2]) self.assertEqual(('info_end',), result[3]) return result[4:] def consume_song_list(self, result): self.assertEqual(('songList begin',), result[0]) for i, row in enumerate(result): if row == ('songList end',): return result[1:i], result[i + 1:] self.fail("Couldn't find songList end in result") def consume_directory(self, result): self.assertEqual('directory', result[0][0]) self.assertEqual(('mtime', mtime('.')), result[1]) self.assertEqual(('begin', os.path.split(result[0][1])[1]), result[2]) directory = result[2][1] for i, row in enumerate(result): if row == ('end', directory): return result[3:i], result[i + 1:] self.fail("Couldn't find end %s in result" % directory) def test_empty_tag_cache_has_header(self): result = translator.tracks_to_tag_cache_format([], self.media_dir) result = self.consume_headers(result) def test_empty_tag_cache_has_song_list(self): result = translator.tracks_to_tag_cache_format([], self.media_dir) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) self.assertEqual(len(song_list), 0) self.assertEqual(len(result), 0) def test_tag_cache_has_header(self): track = Track(uri='file:///dir/subdir/song.mp3') result = translator.tracks_to_tag_cache_format([track], self.media_dir) result = self.consume_headers(result) def test_tag_cache_has_song_list(self): track = Track(uri='file:///dir/subdir/song.mp3') result = translator.tracks_to_tag_cache_format([track], self.media_dir) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) self.assert_(song_list) self.assertEqual(len(result), 0) def test_tag_cache_has_formated_track(self): track = Track(uri='file:///dir/subdir/song.mp3') formated = self.translate(track) result = translator.tracks_to_tag_cache_format([track], self.media_dir) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) self.assertEqual(formated, song_list) self.assertEqual(len(result), 0) def test_tag_cache_has_formated_track_with_key_and_mtime(self): track = Track(uri='file:///dir/subdir/song.mp3') formated = self.translate(track) result = translator.tracks_to_tag_cache_format([track], self.media_dir) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) self.assertEqual(formated, song_list) self.assertEqual(len(result), 0) def test_tag_cache_supports_directories(self): track = Track(uri='file:///dir/subdir/folder/song.mp3') formated = self.translate(track) result = translator.tracks_to_tag_cache_format([track], self.media_dir) result = self.consume_headers(result) dir_data, result = self.consume_directory(result) song_list, result = self.consume_song_list(result) self.assertEqual(len(song_list), 0) self.assertEqual(len(result), 0) song_list, result = self.consume_song_list(dir_data) self.assertEqual(len(result), 0) self.assertEqual(formated, song_list) def test_tag_cache_diretory_header_is_right(self): track = Track(uri='file:///dir/subdir/folder/sub/song.mp3') result = translator.tracks_to_tag_cache_format([track], self.media_dir) result = self.consume_headers(result) dir_data, result = self.consume_directory(result) self.assertEqual(('directory', 'folder/sub'), dir_data[0]) self.assertEqual(('mtime', mtime('.')), dir_data[1]) self.assertEqual(('begin', 'sub'), dir_data[2]) def test_tag_cache_suports_sub_directories(self): track = Track(uri='file:///dir/subdir/folder/sub/song.mp3') formated = self.translate(track) result = translator.tracks_to_tag_cache_format([track], self.media_dir) result = self.consume_headers(result) dir_data, result = self.consume_directory(result) song_list, result = self.consume_song_list(result) self.assertEqual(len(song_list), 0) self.assertEqual(len(result), 0) dir_data, result = self.consume_directory(dir_data) song_list, result = self.consume_song_list(result) self.assertEqual(len(result), 0) self.assertEqual(len(song_list), 0) song_list, result = self.consume_song_list(dir_data) self.assertEqual(len(result), 0) self.assertEqual(formated, song_list) def test_tag_cache_supports_multiple_tracks(self): tracks = [ Track(uri='file:///dir/subdir/song1.mp3'), Track(uri='file:///dir/subdir/song2.mp3'), ] formated = [] formated.extend(self.translate(tracks[0])) formated.extend(self.translate(tracks[1])) result = translator.tracks_to_tag_cache_format(tracks, self.media_dir) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) self.assertEqual(formated, song_list) self.assertEqual(len(result), 0) def test_tag_cache_supports_multiple_tracks_in_dirs(self): tracks = [ Track(uri='file:///dir/subdir/song1.mp3'), Track(uri='file:///dir/subdir/folder/song2.mp3'), ] formated = [] formated.append(self.translate(tracks[0])) formated.append(self.translate(tracks[1])) result = translator.tracks_to_tag_cache_format(tracks, self.media_dir) result = self.consume_headers(result) dir_data, result = self.consume_directory(result) song_list, song_result = self.consume_song_list(dir_data) self.assertEqual(formated[1], song_list) self.assertEqual(len(song_result), 0) song_list, result = self.consume_song_list(result) self.assertEqual(len(result), 0) self.assertEqual(formated[0], song_list) class TracksToDirectoryTreeTest(unittest.TestCase): def setUp(self): self.media_dir = '/root' def test_no_tracks_gives_emtpy_tree(self): tree = translator.tracks_to_directory_tree([], self.media_dir) self.assertEqual(tree, ({}, [])) def test_top_level_files(self): tracks = [ Track(uri='file:///root/file1.mp3'), Track(uri='file:///root/file2.mp3'), Track(uri='file:///root/file3.mp3'), ] tree = translator.tracks_to_directory_tree(tracks, self.media_dir) self.assertEqual(tree, ({}, tracks)) def test_single_file_in_subdir(self): tracks = [Track(uri='file:///root/dir/file1.mp3')] tree = translator.tracks_to_directory_tree(tracks, self.media_dir) expected = ({'dir': ({}, tracks)}, []) self.assertEqual(tree, expected) def test_single_file_in_sub_subdir(self): tracks = [Track(uri='file:///root/dir1/dir2/file1.mp3')] tree = translator.tracks_to_directory_tree(tracks, self.media_dir) expected = ({'dir1': ({'dir1/dir2': ({}, tracks)}, [])}, []) self.assertEqual(tree, expected) def test_complex_file_structure(self): tracks = [ Track(uri='file:///root/file1.mp3'), Track(uri='file:///root/dir1/file2.mp3'), Track(uri='file:///root/dir1/file3.mp3'), Track(uri='file:///root/dir2/file4.mp3'), Track(uri='file:///root/dir2/sub/file5.mp3'), ] tree = translator.tracks_to_directory_tree(tracks, self.media_dir) expected = ( { 'dir1': ({}, [tracks[1], tracks[2]]), 'dir2': ( { 'dir2/sub': ({}, [tracks[4]]) }, [tracks[3]] ), }, [tracks[0]] ) self.assertEqual(tree, expected)