def test_window(self): lib = SongFileLibrary() lib.librarian = SongLibrarian() pl = player.init_player("nullbe", lib.librarian) window = QuodLibetWindow(lib, pl, headless=True) assert window in window.windows window.destroy()
def test(self): lib = SongFileLibrary() with temp_filename() as song_fn: song = AudioFile({"~filename": song_fn}) song.sanitize() lib.add([song]) with temp_filename() as xml_fn: with open(xml_fn, "wb") as h: x = get_example_xml(song("~filename"), 1, 1371802107) h.write(x) handler = self.mod.RBDBContentHandler(lib) xml.sax.parse(xml_fn, handler) self.assertEqual(song("~#rating"), 0.2) self.assertEqual(song("~#lastplayed"), 1371802107) self.assertEqual(song("~#playcount"), 1) with open(xml_fn, "wb") as h: x = get_example_xml(song("~filename"), 2, 1371802107 - 1) h.write(x) handler = self.mod.RBDBContentHandler(lib) xml.sax.parse(xml_fn, handler) self.assertEqual(song("~#rating"), 0.4) self.assertEqual(song("~#lastplayed"), 1371802107)
class TFIFOControl(TestCase): def setUp(self): config.init() self.p = NullPlayer() self.l = SongFileLibrary() self.w = gtk.Window() self.fifo = FIFOControl(self.l, self.w, self.p) def tearDown(self): self.p.destroy() self.l.destroy() self.w.destroy() config.quit() def __send(self, command): f = open(const.CONTROL, "wb") f.write(command) f.close() while gtk.events_pending(): gtk.main_iteration() def test_player(self): self.__send("previous") self.__send("force_previous") self.__send("next") self.__send("pause") self.__send("play-pause") self.__send("stop") self.__send("volume +1000") self.__send("volume 40") self.__send("volume -10") #self.__send("seek -10") #self.__send("seek +10") #self.__send("seek 0") def test_misc(self): #self.__send("add-directory /dev/null") self.__send("add-file /dev/null") #self.__send("dump-playlist /dev/null") #self.__send("dump_queue /dev/null") #self.__send("enqueue /dev/null") self.__send("enqueue-files /dev/null") #self.__send("filter album=test") #self.__send("focus") #self.__send("hide-window") #self.__send("open-browser 1") #self.__send("order shuffle") self.__send("properties") #self.__send("queue 1") self.__send("quit") #self.__send("random album") #self.__send("refresh") #self.__send("repeat 0") #self.__send("set-browser 1") self.__send("set-rating 0.5")
def setUp(self): config.init() self.library = SongFileLibrary() backend = quodlibet.player.init_backend("nullbe") self.device = backend.init(self.library) self.songs = [AudioFile({"title": x}) for x in ["song1", "song2", "song3"]] for song in self.songs: song.sanitize(fsnative(str(song["title"]))) self.confirmed = False
def setUp(self): config.init() self.library = library = SongFileLibrary() library.librarian = SongLibrarian() library.add(SONGS) self.Kind.init(library) self.b = self.Kind(library)
def init(klass, library): if klass.__library is not None: return klass.__glibrary = library klass.__library = SongFileLibrary("filesystem") library.connect('added', klass.__remove_because_added)
def setUp(self): self.success = False # Testing locally is VERY dangerous without this... self.assertTrue(_TEMP_DIR in PLAYLISTS or os.name == "nt", msg="Failing, don't want to delete %s" % PLAYLISTS) try: shutil.rmtree(PLAYLISTS) except OSError: pass mkdir(PLAYLISTS) init_fake_app() self.lib = quodlibet.browsers.playlists.library = SongFileLibrary() self.lib.librarian = SongLibrarian() all_songs = SONGS + [self.ANOTHER_SONG] for af in all_songs: af.sanitize() self.lib.add(all_songs) self.big = pl = FileBackedPlaylist.new(PLAYLISTS, "Big", self.lib) pl.extend(SONGS) pl.write() self.small = pl = FileBackedPlaylist.new(PLAYLISTS, "Small", self.lib) pl.extend([self.ANOTHER_SONG]) pl.write() PlaylistsBrowser.init(self.lib) self.bar = PlaylistsBrowser(self.lib) self.bar.connect('songs-selected', self._expected) self.bar._select_playlist(self.bar.playlists()[0]) self.expected = None
def test_header_menu(self): from quodlibet import browsers from quodlibet.library import SongLibrarian song = AudioFile({"~filename": fsnative(u"/dev/null")}) song.sanitize() self.songlist.set_songs([song]) library = SongFileLibrary() library.librarian = SongLibrarian() browser = browsers.get("SearchBar")(library) self.songlist.set_column_headers(["foo"]) self.assertFalse(self.songlist.Menu("foo", browser, library)) sel = self.songlist.get_selection() sel.select_all() self.assertTrue(self.songlist.Menu("foo", browser, library))
def setUp(self): config.init() self.songlist = SongList(SongFileLibrary()) self.orders_changed = 0 def orders_changed_cb(*args): self.orders_changed += 1 self.songlist.connect("orders-changed", orders_changed_cb)
def test__on_new_playlist_activate(self): main = qltk.MenuItem('Menu') menu = StubbedPlaylistMenu(self.SONGS, PlaylistLibrary(SongFileLibrary())) main.set_submenu(menu) pl = menu._on_new_playlist_activate(main, self.SONGS) self.failUnless(pl, msg="No playlists added") self.failUnlessEqual(pl.songs, self.SONGS)
def setUp(self): config.init() self.lib = SongFileLibrary() self.songlist = SongList(self.lib) assert not self.lib.librarian, "not expecting a librarian - leaky test?" self.orders_changed = 0 self.songs_removed: List[Set] = [] def orders_changed_cb(*args): self.orders_changed += 1 def orders_removed_cb(songlist, removed): self.songs_removed.append(removed) self.__sigs = [ self.songlist.connect("orders-changed", orders_changed_cb), self.songlist.connect("songs-removed", orders_removed_cb) ]
def test__on_new_playlist_activate(self): main = qltk.MenuItem('Menu') menu = StubbedPlaylistMenu(self.SONGS, PlaylistLibrary(SongFileLibrary())) main.set_submenu(menu) # Run it (with stubbed dialog) pl = menu._on_new_playlist_activate(main, self.SONGS) assert pl, "No playlists added" assert pl.name == FIXED_NAME, "Wrong name used" assert pl.songs == self.SONGS
def setUp(self): quodlibet.config.init() self.lib = quodlibet.browsers.tracks.library = SongFileLibrary() quodlibet.browsers.tracks.library.librarian = SongLibrarian() for af in self.SONGS: af.sanitize() self.lib.add(self.SONGS) self._dir = mkdtemp() self.pl = FileBackedPlaylist.new(self._dir, "Foobar", self.lib, self.lib.playlists) self.pl.extend(self.SONGS)
def setUp(self): config.init() class App(Application): browser = None app = App() app.player = NullPlayer() app.library = SongFileLibrary() app.library.librarian = SongLibrarian() app.browser = EmptyBar(app.library, True) app.window = Gtk.OffscreenWindow() self.fifo = FIFOControl(app)
def setUp(self): self.success = False # Testing locally is VERY dangerous without this... self.assertTrue(_TEMP_DIR in _DEFAULT_PLAYLIST_DIR or os.name == "nt", msg="Failing, don't want to delete %s" % _DEFAULT_PLAYLIST_DIR) try: shutil.rmtree(_DEFAULT_PLAYLIST_DIR) except OSError: pass mkdir(_DEFAULT_PLAYLIST_DIR) init_fake_app() self.lib = quodlibet.browsers.playlists.library = SongFileLibrary() self.lib.librarian = SongLibrarian() for af in self.ALL_SONGS: af.sanitize() self.lib.add(self.ALL_SONGS) self.big = pl = FileBackedPlaylist.new(_DEFAULT_PLAYLIST_DIR, "Big", self.lib, self.lib.playlists) pl.extend(SONGS) pl.write() self.small = pl = XSPFBackedPlaylist.new(_DEFAULT_PLAYLIST_DIR, "Small", self.lib, self.lib.playlists) pl.extend([self.ANOTHER_SONG]) pl.write() PlaylistsBrowser.init(self.lib) self.bar = PlaylistsBrowser(self.lib, self.MockConfirmerAccepting) self.bar.connect('songs-selected', self._expected) self.bar._select_playlist(self.bar.playlists()[0]) self.expected = None # Uses the declining confirmer. self.bar_decline = PlaylistsBrowser(self.lib, self.MockConfirmerDeclining) self.bar_decline.connect('songs-selected', self._expected_decline) self.bar_decline._select_playlist(self.bar_decline.playlists()[0]) # Note that _do() uses self.expected, but _do() is not called by the # testcase for declining the prompt. Tests fail with a shared expected. self.expected_decline = None
def init_fake_app(): from quodlibet import app from quodlibet import browsers from quodlibet.player.nullbe import NullPlayer from quodlibet.library import SongFileLibrary from quodlibet.library.librarians import SongLibrarian from quodlibet.qltk.quodlibetwindow import QuodLibetWindow, PlayerOptions from quodlibet.util.cover import CoverManager browsers.init() app.name = "Quod Libet" app.id = "io.github.quodlibet.QuodLibet" app.player = NullPlayer() app.library = SongFileLibrary() app.library.librarian = SongLibrarian() app.cover_manager = CoverManager() app.window = QuodLibetWindow(app.library, app.player, headless=True) app.player_options = PlayerOptions(app.window)
def setUp(self): self.lib = lib = SongFileLibrary() self.received = [] def listen(name, items): self.received.append(name) self._sigs = [ connect_obj(lib, 'added', listen, 'added'), connect_obj(lib, 'changed', listen, 'changed'), connect_obj(lib, 'removed', listen, 'removed'), ] self.playlists = lib.playlists self._asigs = [ connect_obj(self.playlists, 'added', listen, 'pl_added'), connect_obj(self.playlists, 'changed', listen, 'pl_changed'), connect_obj(self.playlists, 'removed', listen, 'pl_removed'), ] songs = AFrange(3) self.lib.add(songs)
class TSongsMenu(TestCase): def _confirmer(self, *args): self.confirmed = True return False def setUp(self): config.init() self.library = SongFileLibrary() backend = quodlibet.player.init_backend("nullbe") self.device = backend.init(self.library) self.songs = [AudioFile({"title": x}) for x in ["song1", "song2", "song3"]] for song in self.songs: song.sanitize(fsnative(str(song["title"]))) self.confirmed = False def test_empty(self): self.menu = self.empty_menu_with() self.failIf(len(self.menu)) def test_simple(self): self.menu = SongsMenu(self.library, self.songs, plugins=False) def test_playlists(self): self.menu = self.empty_menu_with(playlists=True) self.failUnlessEqual(len(self.menu), 1) self.failUnless(self.menu.get_children()[0].props.sensitive) self.songs[0].can_add = False self.menu = self.empty_menu_with(playlists=True) self.failUnlessEqual(len(self.menu), 1) self.failIf(self.menu.get_children()[0].props.sensitive) def test_queue(self): self.menu = self.empty_menu_with(queue=True) self.failUnlessEqual(len(self.menu), 1) self.failUnless(self.menu.get_children()[0].props.sensitive) self.songs[0].can_add = False self.menu = self.empty_menu_with(queue=True) self.failUnlessEqual(len(self.menu), 1) self.failIf(self.menu.get_children()[0].props.sensitive) def test_remove(self): self.menu = self.empty_menu_with(remove=True, removal_confirmer=self._confirmer) self.failUnlessEqual(len(self.menu), 1) item = self.menu.get_children()[0] self.failIf(item.props.sensitive) item.activate() self.failUnless(self.confirmed, "Should have confirmed song removal") def test_remove_sensitive(self): self.library.add(self.songs) self.menu = self.empty_menu_with(remove=True) self.failUnlessEqual(len(self.menu), 1) self.failUnless(self.menu.get_children()[0].props.sensitive) def test_delete(self): self.menu = self.empty_menu_with(delete=True) self.failUnlessEqual(len(self.menu), 1) self.failUnless(self.menu.get_children()[0].props.sensitive) self.songs[0].is_file = False self.menu = self.empty_menu_with(delete=True) self.failIf(self.menu.get_children()[0].props.sensitive) def test_show_files(self): self.menu = self.empty_menu_with(show_files=True) self.failUnlessEqual(len(self.menu), 1) self.failUnless(self.menu.get_children()[0].props.sensitive) item = self.menu.get_children()[0] self.failUnless(item.props.sensitive) def test_show_files_remote_songs(self): self.songs = self.library.songs = [an_rf(1)] self.menu = self.empty_menu_with(show_files=True) self.failIf(len(self.menu)) def test_show_files_too_many_songs(self): self.songs = self.library.songs = [an_af(i) for i in range(50)] self.menu = self.empty_menu_with(show_files=True) item = self.menu.get_children()[0] self.failIf(item.props.sensitive, msg="Should have disabled show files for 50 files") def test_download(self): def choose(*args, **kwargs): return [mkdtemp()] self.songs = self.library.songs = [an_rf(i) for i in range(3)] self.menu = self.empty_menu_with(download=True, folder_chooser=choose) last = self.menu.get_children()[-1] assert last.props.sensitive, "should have enabled download for remotes" # TODO: some useful assertions, without needing a UI def empty_menu_with(self, plugins=False, playlists=False, queue=False, remove=False, delete=False, edit=False, ratings=False, show_files=False, download=False, removal_confirmer=None, folder_chooser=None): return SongsMenu(self.library, self.songs, plugins=plugins, playlists=playlists, queue=queue, remove=remove, delete=delete, edit=edit, ratings=ratings, show_files=show_files, removal_confirmer=removal_confirmer, download=download, folder_chooser=folder_chooser) def tearDown(self): self.device.destroy() self.library.destroy() try: self.menu.destroy() except AttributeError: pass else: del(self.menu) config.quit()
class StorageDevice(Device): protocol = 'storage' defaults = { 'pattern': '<artist>/<album>/<title>', 'covers': True, 'unclutter': True, } __library = None __pattern = None def __init__(self, backend_id, device_id): super(StorageDevice, self).__init__(backend_id, device_id) filename = escape_filename(device_id) self.__library_path = os.path.join(CACHE, filename) self.__library_name = device_id def __set_pattern(self, widget=None): self.__pattern = FileFromPattern( os.path.join(self.mountpoint, self['pattern'])) def Properties(self): props = [] entry = Gtk.Entry() entry.set_text(self['pattern']) entry.connect_after('changed', self.__set_pattern) props.append((_("_Filename pattern:"), entry, 'pattern')) check = Gtk.CheckButton() check.set_active(self['covers']) props.append((_("Copy _album covers"), check, 'covers')) check = Gtk.CheckButton() check.set_active(self['unclutter']) props.append( (_("_Remove unused covers and directories"), check, 'unclutter')) return props def list(self, wlb): self.__load_library() wlb.setup() next = self.__library.rebuild([self.mountpoint]).next while True: if wlb.quit: wlb.hide() break if not wlb.paused: try: next() except StopIteration: break Gtk.main_iteration() self.__save_library() return self.__library.values() def contains(self, song): return song in self.__library def copy(self, parent_widget, song): if not self.__pattern: self.__set_pattern() target = strip_win32_incompat_from_path(self.__pattern.format(song)) dirname = os.path.dirname(target) if os.path.exists(target): dialog = ConfirmFileReplace(parent_widget, target) resp = dialog.run() if resp == ConfirmFileReplace.RESPONSE_REPLACE: try: # Remove the current song self.__library.remove([self.__library[target]]) except KeyError: pass else: return False try: if not os.path.isdir(dirname): os.makedirs(dirname) shutil.copyfile(song['~filename'], target) if self['covers']: coverfile = os.path.join(dirname, 'folder.jpg') cover = app.cover_manager.get_cover(song) if cover and mtime(cover.name) > mtime(coverfile): image = GdkPixbuf.Pixbuf.new_from_file_at_size( cover.name, 200, 200) image.savev(coverfile, "jpeg", [], []) song = copy.deepcopy(song) song.sanitize(target) self.__library.add([song]) return song except (OSError, IOError, GLib.GError) as exc: encoding = util.get_locale_encoding() return str(exc).decode(encoding, 'replace') def delete(self, parent_widget, song): try: path = song['~filename'] dir = os.path.dirname(path) os.unlink(path) self.__library.remove([song]) if self['unclutter']: files = glob(dir + '/*') if len(files) == 1 and os.path.isfile(files[0]) and \ os.path.basename(files[0]) == 'folder.jpg': os.unlink(files[0]) try: os.removedirs(os.path.dirname(path)) except OSError: pass return True except (OSError, IOError) as exc: encoding = util.get_locale_encoding() return str(exc).decode(encoding, 'replace') def cleanup(self, wlb, action): self.__save_library() return True def close(self): if self.__library: self.__library.destroy() self.__library = None def __load_library(self): if self.__library is None: self.__library = SongFileLibrary(self.__library_name) if os.path.isfile(self.__library_path): self.__library.load(self.__library_path) def __save_library(self): self.__library.save(self.__library_path)
class TSongList(TestCase): HEADERS = [ "acolumn", "~#lastplayed", "~foo~bar", "~#rating", "~#length", "~dirname", "~#track" ] def setUp(self): config.init() self.lib = SongFileLibrary() self.songlist = SongList(self.lib) assert not self.lib.librarian, "not expecting a librarian - leaky test?" self.orders_changed = 0 self.songs_removed: List[Set] = [] def orders_changed_cb(*args): self.orders_changed += 1 def orders_removed_cb(songlist, removed): self.songs_removed.append(removed) self.__sigs = [ self.songlist.connect("orders-changed", orders_changed_cb), self.songlist.connect("songs-removed", orders_removed_cb) ] def test_set_all_column_headers(self): SongList.set_all_column_headers(self.HEADERS) headers = [col.header_name for col in self.songlist.get_columns()] self.failUnlessEqual(headers, self.HEADERS) def test_set_column_headers(self): self.songlist.set_column_headers(self.HEADERS) headers = [col.header_name for col in self.songlist.get_columns()] self.failUnlessEqual(headers, self.HEADERS) def test_drop(self): self.songlist.enable_drop() self.songlist.disable_drop() def test_sort_by(self): self.songlist.set_column_headers(["one", "two", "three"]) for key, order in [("one", True), ("two", False), ("three", False)]: self.songlist.set_sort_orders([(key, order)]) self.failUnlessEqual(self.songlist.get_sort_orders(), [(key, order)]) self.songlist.toggle_column_sort(self.songlist.get_columns()[-1]) self.failUnlessEqual(self.songlist.get_sort_orders(), [("three", True)]) def test_sort_orders(self): s = self.songlist s.set_column_headers(["foo", "quux", "bar"]) values = [("foo", True), ("bar", False)] s.set_sort_orders(values) self.assertEqual(s.get_sort_orders(), values) s.toggle_column_sort(s.get_columns()[1], replace=False) self.assertEqual(s.get_sort_orders(), values + [("quux", False)]) s.toggle_column_sort(s.get_columns()[1], replace=True) self.assertEqual(s.get_sort_orders(), [("quux", False)]) def test_toggle_sort(self): s = self.songlist s.set_column_headers(["foo"]) self.assertEqual(self.orders_changed, 1) s.toggle_column_sort(s.get_columns()[0], replace=True) self.assertEqual(self.orders_changed, 2) self.assertEqual(s.get_sort_orders(), [("foo", False)]) s.toggle_column_sort(s.get_columns()[0], replace=True) self.assertEqual(self.orders_changed, 3) self.assertEqual(s.get_sort_orders(), [("foo", True)]) def test_clear_sort(self): s = self.songlist s.set_column_headers(["foo"]) s.toggle_column_sort(s.get_columns()[0], replace=True) self.assertTrue(s.get_sort_orders()) s.clear_sort() self.assertFalse(s.get_sort_orders()) def test_not_sortable(self): s = self.songlist s.sortable = False s.set_column_headers(["foo"]) s.toggle_column_sort(s.get_columns()[0]) self.assertEqual(self.orders_changed, 0) self.assertFalse(s.get_sort_orders()) def test_find_default_sort_column(self): s = self.songlist self.assertTrue(s.find_default_sort_column() is None) s.set_column_headers(["~#track"]) self.assertTrue(s.find_default_sort_column()) def test_inline_search_state(self): self.assertEqual(self.songlist.get_search_column(), 0) self.assertTrue(self.songlist.get_enable_search()) def test_set_songs(self): self.songlist.set_songs([], sorted=True) self.songlist.set_songs([], sorted=False) self.songlist.set_songs([], scroll_select=True) self.songlist.set_songs([], scroll_select=False) self.songlist.set_songs([], scroll=True) self.songlist.set_songs([], scroll=False) def test_set_songs_restore_select(self): song = AudioFile({"~filename": "/dev/null"}) self.songlist.add_songs([song]) sel = self.songlist.get_selection() sel.select_path(Gtk.TreePath.new_first()) self.songlist.set_songs([song], scroll_select=True) self.assertEqual(self.songlist.get_selected_songs(), [song]) song2 = AudioFile({"~filename": "/dev/null"}) self.songlist.set_songs([song2], scroll_select=True) self.assertEqual(self.songlist.get_selected_songs(), []) def test_set_songs_no_restore_select(self): song = AudioFile({"~filename": "/dev/null"}) self.songlist.add_songs([song]) model = self.songlist.get_model() model.go_to(song) self.assertIs(model.current, song) # only restore if there was a selected one self.songlist.set_songs([song], scroll_select=True) self.assertEqual(self.songlist.get_selected_songs(), []) def test_get_selected_songs(self): song = AudioFile({"~filename": "/dev/null"}) self.songlist.add_songs([song]) sel = self.songlist.get_selection() sel.select_path(Gtk.TreePath.new_first()) self.assertEqual(self.songlist.get_selected_songs(), [song]) self.assertEqual(self.songlist.get_first_selected_song(), song) sel.unselect_all() self.assertEqual(self.songlist.get_selected_songs(), []) self.assertIs(self.songlist.get_first_selected_song(), None) def test_add_songs(self): song = AudioFile({"~filename": "/dev/null"}) # unsorted self.songlist.add_songs([song]) self.songlist.add_songs([song]) # sorted self.songlist.set_column_headers(["foo"]) self.songlist.toggle_column_sort(self.songlist.get_columns()[0]) self.songlist.add_songs([]) self.songlist.add_songs([song]) self.songlist.add_songs([song]) self.assertEqual(self.songlist.get_songs(), [song] * 4) def test_remove_songs(self): song = AudioFile({"~filename": "/dev/null"}) song.sanitize() self.lib.add([song]) assert song in self.lib, "Broken library?" self.songlist.add_songs([song]) assert set(self.songlist.get_songs()) == {song} self.lib.remove([song]) assert not list(self.lib), "Didn't get removed" run_gtk_loop() assert self.songs_removed == [{song} ], f"Signal not emitted: {self.__sigs}" def test_header_menu(self): song = AudioFile({"~filename": fsnative(u"/dev/null")}) song.sanitize() self.songlist.set_songs([song]) library = self.lib librarian = SongLibrarian() librarian.register(self.lib, "test") self.lib.librarian = librarian browser = TrackList(library) self.songlist.set_column_headers(["foo"]) self.assertFalse(self.songlist.Menu("foo", browser, library)) sel = self.songlist.get_selection() sel.select_all() self.assertTrue(self.songlist.Menu("foo", browser, library)) librarian.destroy() self.lib.librarian = None def test_get_columns_migrated(self): self.failIf(config.get("settings", "headers", None)) columns = "~album,~#replaygain_track_gain,foobar" config.set("settings", "columns", columns) self.failUnlessEqual(get_columns(), ["~album", "~#replaygain_track_gain", "foobar"]) self.failIf(config.get("settings", "headers", None)) def test_get_set_columns(self): self.failIf(config.get("settings", "headers", None)) self.failIf(config.get("settings", "columns", None)) columns = ["first", "won't", "two words", "4"] set_columns(columns) self.failUnlessEqual(columns, get_columns()) columns += ["~~another~one"] set_columns(columns) self.failUnlessEqual(columns, get_columns()) self.failIf(config.get("settings", "headers", None)) def test_header_tag_split(self): self.assertEqual(header_tag_split("foo"), ["foo"]) self.assertEqual(header_tag_split("~foo~bar"), ["foo", "bar"]) self.assertEqual(header_tag_split("<foo>"), ["foo"]) self.assertEqual(header_tag_split("<~foo~bar>"), ["foo", "bar"]) self.assertEqual(header_tag_split("pattern <~foo~bar>"), ["foo", "bar"]) def test_get_sort_tag(self): self.assertEqual(get_sort_tag("~#track"), "") self.assertEqual(get_sort_tag("artist"), "artistsort") self.assertEqual(get_sort_tag("date"), "date") self.assertEqual(get_sort_tag("~artist~date"), "~artistsort~date") self.assertEqual(get_sort_tag("~date~artist"), "~date~artistsort") self.assertEqual(get_sort_tag("composer"), "composersort") self.assertEqual(get_sort_tag("originalartist"), "originalartistsort") def test_check_sensible_menu_items(self): col = SongListColumn("title") menu = self.songlist._menu(col) submenus = [item.get_submenu() for item in menu.get_children()] names = { item.get_label() for child in submenus if child and not isinstance(child, Gtk.SeparatorMenuItem) for item in child.get_children() } assert {"Title", "Genre", "Comment", "Artist"} < names def tearDown(self): for sig in self.__sigs: self.songlist.disconnect(sig) self.songlist.destroy() self.lib.destroy() config.quit()
def setUp(self): self.pl_lib = PlaylistLibrary(SongFileLibrary())
class StorageDevice(Device): protocol = 'storage' defaults = { 'pattern': '<artist>/<album>/<title>', 'covers': True, 'unclutter': True, } __library = None __pattern = None def __init__(self, backend_id, device_id): super(StorageDevice, self).__init__(backend_id, device_id) filename = escape_filename(device_id) self.__library_path = os.path.join(CACHE, filename) self.__library_name = device_id def __set_pattern(self, widget=None): self.__pattern = FileFromPattern( os.path.join(self.mountpoint, self['pattern'])) def Properties(self): props = [] entry = Gtk.Entry() entry.set_text(self['pattern']) entry.connect_after('changed', self.__set_pattern) props.append((_("_Filename pattern:"), entry, 'pattern')) check = Gtk.CheckButton() check.set_active(self['covers']) props.append((_("Copy _album covers"), check, 'covers')) check = Gtk.CheckButton() check.set_active(self['unclutter']) props.append((_("_Remove unused covers and directories"), check, 'unclutter')) return props def list(self, wlb): self.__load_library() wlb.setup() next = self.__library.rebuild([self.mountpoint]).next while True: if wlb.quit: wlb.hide() break if not wlb.paused: try: next() except StopIteration: break Gtk.main_iteration() self.__save_library() return self.__library.values() def contains(self, song): return song in self.__library def copy(self, parent_widget, song): if not self.__pattern: self.__set_pattern() target = strip_win32_incompat_from_path(self.__pattern.format(song)) dirname = os.path.dirname(target) if os.path.exists(target): dialog = ConfirmFileReplace(parent_widget, target) resp = dialog.run() if resp == ConfirmFileReplace.RESPONSE_REPLACE: try: # Remove the current song self.__library.remove([self.__library[target]]) except KeyError: pass else: return False try: if not os.path.isdir(dirname): os.makedirs(dirname) shutil.copyfile(song['~filename'], target) if self['covers']: coverfile = os.path.join(dirname, 'folder.jpg') cover = app.cover_manager.get_cover(song) if cover and mtime(cover.name) > mtime(coverfile): image = GdkPixbuf.Pixbuf.new_from_file_at_size( cover.name, 200, 200) image.savev(coverfile, "jpeg", [], []) song = copy.deepcopy(song) song.sanitize(target) self.__library.add([song]) return song except (OSError, IOError, GLib.GError) as exc: encoding = util.get_locale_encoding() return str(exc).decode(encoding, 'replace') def delete(self, parent_widget, song): try: path = song['~filename'] dir = os.path.dirname(path) os.unlink(path) self.__library.remove([song]) if self['unclutter']: files = glob(dir + '/*') if len(files) == 1 and os.path.isfile(files[0]) and \ os.path.basename(files[0]) == 'folder.jpg': os.unlink(files[0]) try: os.removedirs(os.path.dirname(path)) except OSError: pass return True except (OSError, IOError) as exc: encoding = util.get_locale_encoding() return str(exc).decode(encoding, 'replace') def cleanup(self, wlb, action): self.__save_library() return True def close(self): if self.__library: self.__library.destroy() self.__library = None def __load_library(self): if self.__library is None: self.__library = SongFileLibrary(self.__library_name) if os.path.isfile(self.__library_path): self.__library.load(self.__library_path) def __save_library(self): self.__library.save(self.__library_path)
def __load_library(self): if self.__library is None: self.__library = SongFileLibrary(self.__library_name) if os.path.isfile(self.__library_path): self.__library.load(self.__library_path)
def test(self): lib = SongFileLibrary() MaskedBox(lib).destroy()
def Library(self): lib = SongFileLibrary(watch_dirs=[text2fsn(str(self.temp_path))]) # Setup needs copools run_gtk_loop() return lib
def test(self): lib = SongFileLibrary() with temp_filename() as song_fn: song = AudioFile({"~filename": song_fn}) song.sanitize() lib.add([song]) # test recovery of basic song data = {"path": song("~filename"), "rating": 1, "playcount": 1, "skipcount": 2, "lastplayed": 1371802107, "added": 1260691996} db = get_example_db(data["path"], data["rating"], data["playcount"], data["skipcount"], data["lastplayed"], data["added"]) importer = self.mod.BansheeDBImporter(lib) importer.read(db) count = importer.finish() db.close() self.assertEqual(song("~#rating"), data["rating"] / 5.0) self.assertEqual(song("~#playcount"), data["playcount"]) self.assertEqual(song("~#skipcount"), data["skipcount"]) self.assertEqual(song("~#lastplayed"), data["lastplayed"]) self.assertEqual(song("~#added"), data["added"]) self.assertEqual(count, 1) # test recovery of different version of same song data_mod = {"path": song("~filename"), "rating": 2, "playcount": 4, "skipcount": 1, "lastplayed": data["lastplayed"] - 1, "added": data["added"] + 1} db = get_example_db(data_mod["path"], data_mod["rating"], data_mod["playcount"], data_mod["skipcount"], data_mod["lastplayed"], data_mod["added"]) importer = self.mod.BansheeDBImporter(lib) importer.read(db) count = importer.finish() db.close() self.assertEqual(song("~#rating"), data_mod["rating"] / 5.0) self.assertEqual(song("~#playcount"), data_mod["playcount"]) self.assertEqual(song("~#skipcount"), data_mod["skipcount"]) self.assertEqual(song("~#lastplayed"), data["lastplayed"]) self.assertEqual(song("~#added"), data["added"]) self.assertEqual(count, 1) # test that no recovery is performed when data is identical db = get_example_db(data_mod["path"], data_mod["rating"], data_mod["playcount"], data_mod["skipcount"], data_mod["lastplayed"], data_mod["added"]) importer = self.mod.BansheeDBImporter(lib) importer.read(db) count = importer.finish() db.close() self.assertEqual(count, 0)
def setUp(self): self.sfLib = SongFileLibrary() self.plLib = PlaylistLibrary(self.sfLib)
class TPlaylistUtil(TestCase): PLAYLIST_FILE_PATH = get_data_path('test.m3u8') sfLib: SongFileLibrary = None plLib: PlaylistLibrary = None def setUp(self): self.sfLib = SongFileLibrary() self.plLib = PlaylistLibrary(self.sfLib) def tearDown(self): self.plLib.destroy() self.sfLib.destroy() def test_dir_for(self): # uri format of files added via drag and drop or add button # (Gtk.SelectionData.get_uris()): file:///path/to/file.ext url_based_file: addinfourl = urlopen("file:///" + self.PLAYLIST_FILE_PATH) reader_based_file: BufferedReader = open(self.PLAYLIST_FILE_PATH, "rb") try: dir_of_url_based_file: str = _dir_for(url_based_file) self.assertEqual( os.path.realpath(os.path.dirname(self.PLAYLIST_FILE_PATH)), os.path.realpath(dir_of_url_based_file), "determining the directory of url based files" " should result in a correct path") dir_of_reader_based_file: str = _dir_for(reader_based_file) self.assertEqual( os.path.realpath(os.path.dirname(self.PLAYLIST_FILE_PATH)), os.path.realpath(dir_of_reader_based_file, ), "determining the directory of reader based files" " should result in a correct path") finally: url_based_file.close() reader_based_file.close() def test_parse_m3u8(self): fileName = os.path.basename(self.PLAYLIST_FILE_PATH) playlist: Playlist = None with open(self.PLAYLIST_FILE_PATH, "rb") as file: try: playlist = parse_m3u(file, fileName, self.sfLib, self.plLib) except: assert False, ("parsing m3u8 playlists in correct format" " should not cause errors") self.assertIsNotNone(playlist, ("parsing an m3u8 playlist in the correct format" " should result in a playlist")) # the test.m3u8 contains: # - 3 existing and supported audio files from the tests/data folder: # lame.mp3, test.wav, sine-110hz.flac # - 1 non existing file: non_existing_audio_file.mp3 # - 1 not supported file: test.jpg # parsing the file correctly should result in a playlist with 3 entries self.assertEqual( 3, len(playlist), "only existing files should be added to the playlist")
def setUp(self): config.init() self.p = NullPlayer() self.l = SongFileLibrary() self.w = gtk.Window() self.fifo = FIFOControl(self.l, self.w, self.p)