def test_album_key(self): album_key_tests = [ ({}, ('', (), ())), ({ 'album': 'foo' }, ('', ('foo', ), ())), ({ 'labelid': 'foo' }, ('foo', (), ())), ({ 'musicbrainz_albumid': 'foo' }, ('foo', (), ())), ({ 'album': 'foo', 'labelid': 'bar' }, ('bar', ('foo', ), ())), ({ 'album': 'foo', 'labelid': 'bar', 'musicbrainz_albumid': 'quux' }, ('bar', ('foo', ), ())), ({ 'albumartist': 'a' }, ('', (), ('a', ))), ] for tags, expected in album_key_tests: afile = AudioFile(**tags) afile.sanitize(fsnative(u'/dir/fn')) self.failUnlessEqual(afile.album_key, expected)
class TRatingsMenuItem(TestCase): def setUp(self): config.RATINGS = config.HardCodedRatingsPrefs() self.failUnlessEqual(config.RATINGS.number, NUM_RATINGS) self.library = SongLibrary() self.library.librarian = SongLibrarian() self.af = AudioFile({"~filename": fsnative(u"/foo"), "~#rating": 1.0}) self.af.sanitize() self.rmi = RatingsMenuItem([self.af], self.library) def tearDown(self): self.rmi.destroy() self.library.destroy() self.library.librarian.destroy() def test_menuitem_children(self): children = [mi for mi in self.rmi.get_submenu().get_children() if isinstance(mi, Gtk.CheckMenuItem)] self.failUnlessEqual(len(children), NUM_RATINGS + 1) highest = children[-1] self.failUnlessEqual(highest.get_active(), True) self.failUnlessEqual(children[1].get_active(), False) def test_set_remove_rating(self): self.rmi.set_rating(0.5, [self.af], self.library) self.failUnless(self.af.has_rating) self.failUnlessEqual(self.af('~#rating'), 0.5) self.rmi.remove_rating([self.af], self.library) self.failIf(self.af.has_rating)
def test_masked_handling(self): if os.name == "nt": # FIXME: masking isn't properly implemented on Windows return # playlists can contain songs and paths for masked handling.. lib = FileLibrary("foobar") with self.wrap("playlist", lib) as pl: song = Fakesong({"date": "2038", "~filename": fsnative(u"/fake")}) song.sanitize() lib.add([song]) # mask and update lib.mask("/") pl.append(song) pl.remove_songs([song]) self.failUnless("/fake" in pl) pl.extend(self.TWO_SONGS) # check if collections can handle the mix self.failUnlessEqual(pl("date"), "2038") # unmask and update lib.unmask("/") pl.add_songs(["/fake"], lib) self.failUnless(song in pl) lib.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)
def test_msic(self): with realized(self.b): self.b.activate() self.b.status_text(1000) self.b.status_text(1) song = AudioFile({"~filename": dummy_path(u"/fake")}) song.sanitize() self.b.scroll(song)
def setUp(self): config.init() player = NullPlayer() song = AudioFile() song.bookmarks = [(10, "bla")] song.sanitize(fsnative(u"/")) player.song = song self.player = player
def test_msic(self): with realized(self.b): self.b.activate() self.b.statusbar(1000) self.b.statusbar(1) song = AudioFile({"~filename": fsnative(u"/fake")}) song.sanitize() self.b.scroll(song)
def setUp(self): config.init() player = NullPlayer() song = AudioFile() song.bookmarks = [(10, "bla")] song.sanitize(fsnative(u"/")) player.song = song self.player = player self.library = SongLibrary()
def test_menuitem(self): library = SongLibrary() library.librarian = SongLibrarian() a = AudioFile({"~filename": fsnative(u"/foo")}) a.sanitize() x = RatingsMenuItem([a], library) x.set_rating(0, [a], library) x.destroy() library.destroy() library.librarian.destroy()
def _print_playing(app, fstring="<artist~album~tracknumber~title>"): from quodlibet.formats import AudioFile from quodlibet.pattern import Pattern song = app.player.info if song is None: song = AudioFile({"~filename": fsnative(u"/")}) song.sanitize() return Pattern(fstring).format(song) + "\n"
def test_sanitize(self): q = AudioFile(quux) b = AudioFile(bar_1_1) q.sanitize() b.pop("~filename") self.failUnlessRaises(ValueError, b.sanitize) n = AudioFile({"artist": u"foo\0bar", "title": u"baz\0", "~filename": fsnative(u"whatever")}) n.sanitize() self.failUnlessEqual(n["artist"], "foo\nbar") self.failUnlessEqual(n["title"], "baz")
def test_sanitize(self): q = AudioFile(quux) b = AudioFile(bar_1_1) q.sanitize() b.pop('~filename') self.failUnlessRaises(ValueError, b.sanitize) n = AudioFile({"artist": u"foo\0bar", "title": u"baz\0", "~filename": fsnative(u"whatever")}) n.sanitize() self.failUnlessEqual(n["artist"], "foo\nbar") self.failUnlessEqual(n["title"], "baz")
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_lyrics_from_file(self): with temp_filename() as filename: af = AudioFile(artist='Motörhead', title='this: again') af.sanitize(filename) lyrics = "blah!\nblasé 😬\n" lyrics_dir = os.path.dirname(af.lyric_filename) mkdir(lyrics_dir) with io.open(af.lyric_filename, "w", encoding='utf-8') as lf: lf.write(str(lyrics)) self.failUnlessEqual( af("~lyrics").splitlines(), lyrics.splitlines()) os.remove(af.lyric_filename) os.rmdir(lyrics_dir)
def getline(key, value): song = AudioFile({"~filename": fsnative(u"/dev/null")}) song.sanitize() song[key] = value lines = format_tags(song).splitlines() if not lines: return "" if len(lines) == 1: return lines[0] # hackery since title defaults to the filename.. for l in lines: if not l.startswith("Title"): return l
def test_lyrics_from_file(self): with temp_filename() as filename: af = AudioFile(artist='Motörhead', title='this: again') af.sanitize(filename) lyrics = "blah!\nblasé 😬\n" lyrics_dir = os.path.dirname(af.lyric_filename) mkdir(lyrics_dir) with io.open(af.lyric_filename, "w", encoding='utf-8') as lf: lf.write(text_type(lyrics)) self.failUnlessEqual(af("~lyrics").splitlines(), lyrics.splitlines()) os.remove(af.lyric_filename) os.rmdir(lyrics_dir)
def getline(key, value): song = AudioFile({"~filename": "/dev/null"}) song.sanitize() song[key] = value lines = format_tags(song).splitlines() if not lines: return "" if len(lines) == 1: return lines[0] # hackery since title defaults to the filename.. for l in lines: if not l.startswith("Title"): return l
def test_album_key(self): album_key_tests = [ ({}, ("", "", "")), ({"album": "foo"}, (("foo",), "", "")), ({"labelid": "foo"}, ("", "", "foo")), ({"musicbrainz_albumid": "foo"}, ("", "", "foo")), ({"album": "foo", "labelid": "bar"}, (("foo",), "", "bar")), ({"album": "foo", "labelid": "bar", "musicbrainz_albumid": "quux"}, (("foo",), "", "bar")), ({"albumartist": "a"}, ("", ("a",), "")), ] for tags, expected in album_key_tests: afile = AudioFile(**tags) afile.sanitize(fsnative(u"/dir/fn")) self.failUnlessEqual(afile.album_key, expected)
def test_lyrics_mp3_is_not_a_valid_lyrics_file(self): # https://github.com/quodlibet/quodlibet/issues/3395 fn = get_data_path('silence-44-s.mp3') with temp_filename() as filename: af = AudioFile(artist='bar', title='foo') af.sanitize(filename) lyrics_dir = os.path.dirname(af.lyric_filename) mkdir(lyrics_dir) try: with open(af.lyric_filename, "wb") as target: with open(fn, "rb") as source: target.write(source.read()) assert "\0" not in af("~lyrics") finally: shutil.rmtree(lyrics_dir)
def test_album_key(self): album_key_tests = [ ({}, ((), (), '')), ({'album': 'foo'}, (('foo',), (), '')), ({'labelid': 'foo'}, ((), (), 'foo')), ({'musicbrainz_albumid': 'foo'}, ((), (), 'foo')), ({'album': 'foo', 'labelid': 'bar'}, (('foo',), (), 'bar')), ({'album': 'foo', 'labelid': 'bar', 'musicbrainz_albumid': 'quux'}, (('foo',), (), 'bar')), ({'albumartist': 'a'}, ((), ('a',), '')), ] for tags, expected in album_key_tests: afile = AudioFile(**tags) afile.sanitize(fsnative(u'/dir/fn')) self.failUnlessEqual(afile.album_key, expected)
def _print_playing(app, fstring=None): from quodlibet.formats import AudioFile from quodlibet.pattern import Pattern if fstring is None: fstring = u"<artist~album~tracknumber~title>" else: fstring = arg2text(fstring) song = app.player.info if song is None: song = AudioFile({"~filename": fsnative(u"/")}) song.sanitize() else: song = app.player.with_elapsed_info(song) return text2fsn(Pattern(fstring).format(song) + u"\n")
def move_song(self, song: AudioFile, new_path: fsnative) -> bool: """Updates the location of a song, without touching the file. :returns: True if it was could be found (and moved) """ existed = True key = song.key print_d(f"Moving {key!r} -> {new_path!r}") try: del self._contents[key] except KeyError: existed = False # Continue - maybe it's already moved song.sanitize(new_path) self._contents[new_path] = song return existed
def test_header_menu(self): from quodlibet import browsers from quodlibet.library import SongLibrary, SongLibrarian song = AudioFile({"~filename": fsnative(u"/dev/null")}) song.sanitize() self.songlist.set_songs([song]) library = SongLibrary() 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 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
class TRatingsMenuItem(TestCase): def setUp(self): config.RATINGS = config.HardCodedRatingsPrefs() self.failUnlessEqual(config.RATINGS.number, NUM_RATINGS) self.library = SongLibrary() self.library.librarian = SongLibrarian() self.af = AudioFile({"~filename": fsnative(u"/foo"), "~#rating": 1.0}) self.af.sanitize() self.rmi = RatingsMenuItem([self.af], self.library) def tearDown(self): self.rmi.destroy() self.library.destroy() self.library.librarian.destroy() def test_menuitem_children(self): children = [ mi for mi in self.rmi.get_submenu().get_children() if isinstance(mi, Gtk.CheckMenuItem) ] self.failUnlessEqual(len(children), NUM_RATINGS + 1) highest = children[-1] self.failUnlessEqual(highest.get_active(), True) self.failUnlessEqual(children[1].get_active(), False) def test_no_rating(self): af = AudioFile({"~filename": fsnative(u"/foobar"), 'artist': 'foo'}) rmi = RatingsMenuItem([af], self.library) children = [ mi for mi in rmi.get_submenu().get_children() if isinstance(mi, Gtk.CheckMenuItem) ] self.failIf(any([c.get_active() for c in children])) def test_set_remove_rating(self): self.rmi.set_rating(0.5, [self.af], self.library) self.failUnless(self.af.has_rating) self.failUnlessEqual(self.af('~#rating'), 0.5) self.rmi.remove_rating([self.af], self.library) self.failIf(self.af.has_rating)
def test_mountpoint(self): song = AudioFile() song["~filename"] = fsnative(u"filename") song.sanitize() assert isinstance(song["~mountpoint"], fsnative) assert isinstance(song.comma("~mointpoint"), str)
from tests import skipUnless from tests.plugin import PluginTestCase, init_fake_app, destroy_fake_app from quodlibet.formats import AudioFile from quodlibet import config from quodlibet import app from quodlibet.compat import iteritems A1 = AudioFile( {'album': u'greatness', 'title': 'excellent', 'artist': 'fooman\ngo', '~#lastplayed': 1234, '~#rating': 0.75, '~filename': fsnative(u'/foo a/b'), "~#length": 123, "albumartist": "aa\nbb", "bpm": "123.5", "tracknumber": "6/7"}) A1.sanitize() A2 = AudioFile( {'album': u'greatness2\ufffe', 'title': 'superlative', 'artist': u'fooman\ufffe', '~#lastplayed': 1234, '~#rating': 1.0, '~filename': fsnative(u'/foo')}) A2.sanitize() MAX_TIME = 3 @skipUnless(dbus, "no dbus") class TMPRIS(PluginTestCase): def setUp(self): self.plugin = self.plugins["mpris"].cls
from quodlibet.qltk.songmodel import PlaylistModel from quodlibet.qltk.controls import Volume FILES = [ AudioFile({"~filename": fsnative(u"/foo/bar1"), "title": "1"}), AudioFile({"~filename": fsnative(u"/foo/bar2"), "title": "2"}), AudioFile({"~filename": fsnative(u"/foo/bar3"), "title": "3"}), ] for file_ in FILES: file_.sanitize() UNKNOWN_FILE = FILES.pop(-1) REAL_FILE = AudioFile({"~filename": get_data_path("empty.ogg")}) REAL_FILE.sanitize() class TPlayer(TestCase): NAME = None def setUp(self): config.init() config.set("player", "gst_pipeline", "fakesink") config.set("settings", "xine_driver", "none") module = player.init_backend(self.NAME) lib = library.init() self.player = module.init(lib.librarian) source = PlaylistModel() source.set(FILES)
from tests import skipUnless from tests.plugin import PluginTestCase, init_fake_app, destroy_fake_app from quodlibet.formats import AudioFile from quodlibet import config from quodlibet import app A1 = AudioFile( {'album': u'greatness', 'title': 'excellent', 'artist': 'fooman\ngo', '~#lastplayed': 1234, '~#rating': 0.75, '~filename': fsnative(u'/foo a/b'), "~#length": 123, "albumartist": "aa\nbb", "bpm": "123.5", "tracknumber": "6/7"}) A1.sanitize() A2 = AudioFile( {'album': u'greatness2\ufffe', 'title': 'superlative', 'artist': u'fooman\ufffe', '~#lastplayed': 1234, '~#rating': 1.0, '~filename': fsnative(u'/foo'), 'discnumber': '4294967296'}) A2.sanitize() MAX_TIME = 3 @skipUnless(dbus, "no dbus") class TMPRIS(PluginTestCase): BUS_NAME = "org.mpris.MediaPlayer2.quodlibet"
# This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. from gi.repository import Gtk from senf import fsnative from tests import TestCase from quodlibet import config from quodlibet.formats import AudioFile from quodlibet.qltk.delete import DeleteDialog, TrashDialog, TrashMenuItem SONG = AudioFile({"~filename": fsnative(u"/dev/null")}) SONG.sanitize() class TDeleteDialog(TestCase): def setUp(self): config.init() def tearDown(self): config.quit() def test_delete_songs(self): dialog = DeleteDialog.for_songs(None, []) dialog.destroy() def test_delete_files(self): dialog = DeleteDialog.for_files(None, [])
def AF(*args, **kwargs): a = AudioFile(*args, **kwargs) a.sanitize() return a
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)
# -*- coding: utf-8 -*- # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation from gi.repository import Gtk from senf import fsnative from tests import TestCase from quodlibet import config from quodlibet.formats import AudioFile from quodlibet.qltk.delete import DeleteDialog, TrashDialog, TrashMenuItem SONG = AudioFile({"~filename": fsnative(u"/dev/null")}) SONG.sanitize() class TDeleteDialog(TestCase): def setUp(self): config.init() def tearDown(self): config.quit() def test_delete_songs(self): dialog = DeleteDialog.for_songs(None, []) dialog.destroy() def test_delete_files(self):
def lyric_filename_search_test_song(self, pathfile): s = AudioFile() s.sanitize(pathfile) s['artist'] = "SpongeBob SquarePants" s['title'] = "Theme Tune" return s
def test_mountpoint(self): song = AudioFile() song["~filename"] = fsnative(u"filename") song.sanitize() assert isinstance(song["~mountpoint"], fsnative) assert isinstance(song.comma("~mointpoint"), text_type)