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 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()
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)
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()