Пример #1
0
class TSongTracker(TestCase):
    def setUp(self):
        config.init()
        self.p = NullPlayer()
        self.w = SongLibrary()
        self.s1 = AudioFile(
            {"~#playcount": 0, "~#skipcount": 0, "~#lastplayed": 10,
             "~filename": "foo", "~#length": 1.5})
        self.s2 = AudioFile(
            {"~#playcount": 0, "~#skipcount": 0, "~#lastplayed": 10,
             "~filename": "foo", "~#length": 1.5})
        self.cm = SongTracker(self.w, self.p, self)
        self.current = None

    def do(self):
        while Gtk.events_pending():
            Gtk.main_iteration()

    def test_destroy(self):
        self.cm.destroy()

    def test_play(self):
        import time
        # Allow at least 2 second to elapse to simulate playing
        self.p.song = self.s1
        self.p.paused = False
        time.sleep(2)
        self.do()
        self.p.emit('song-ended', self.s1, False)
        self.do()
        t = time.time()
        self.assertEquals(self.s1["~#playcount"], 1)
        self.assertEquals(self.s1["~#skipcount"], 0)
        self.failUnless(t - self.s1["~#lastplayed"] <= 1)

    def test_skip(self):
        self.p.emit('song-ended', self.s1, True)
        self.do()
        self.assertEquals(self.s1["~#playcount"], 0)
        self.assertEquals(self.s1["~#skipcount"], 1)
        self.failUnless(self.s1["~#lastplayed"], 10)

    def test_error(self):
        self.current = self.p.song = self.s1
        self.p._error('Test error')
        self.do()
        self.assertEquals(self.s1["~#playcount"], 0)
        self.assertEquals(self.s1["~#skipcount"], 0)
        self.failUnless(self.s1["~#lastplayed"], 10)

    def test_restart(self):
        self.current = self.s1
        self.p.emit('song-ended', self.s1, True)
        self.do()
        self.assertEquals(self.s1["~#playcount"], 0)
        self.assertEquals(self.s1["~#skipcount"], 0)

    def tearDown(self):
        self.w.destroy()
        config.quit()
Пример #2
0
class TSongTracker(TestCase):
    def setUp(self):
        config.init()
        self.p = NullPlayer()
        self.w = SongLibrary()
        self.s1 = AudioFile(
            {"~#playcount": 0, "~#skipcount": 0, "~#lastplayed": 10,
             "~filename": "foo", "~#length": 1.5})
        self.s2 = AudioFile(
            {"~#playcount": 0, "~#skipcount": 0, "~#lastplayed": 10,
             "~filename": "foo", "~#length": 1.5})
        self.cm = SongTracker(self.w, self.p, self)
        self.current = None

    def do(self):
        while Gtk.events_pending():
            Gtk.main_iteration()

    def test_destroy(self):
        self.cm.destroy()

    def test_play(self):
        import time
        # Allow at least 2 second to elapse to simulate playing
        self.p.song = self.s1
        self.p.paused = False
        time.sleep(2)
        self.do()
        self.p.emit('song-ended', self.s1, False)
        self.do()
        t = time.time()
        self.assertEquals(self.s1["~#playcount"], 1)
        self.assertEquals(self.s1["~#skipcount"], 0)
        self.failUnless(t - self.s1["~#lastplayed"] <= 1)

    def test_skip(self):
        self.p.emit('song-ended', self.s1, True)
        self.do()
        self.assertEquals(self.s1["~#playcount"], 0)
        self.assertEquals(self.s1["~#skipcount"], 1)
        self.failUnless(self.s1["~#lastplayed"], 10)

    def test_error(self):
        self.current = self.p.song = self.s1
        self.p._error('Test error')
        self.do()
        self.assertEquals(self.s1["~#playcount"], 0)
        self.assertEquals(self.s1["~#skipcount"], 0)
        self.failUnless(self.s1["~#lastplayed"], 10)

    def test_restart(self):
        self.current = self.s1
        self.p.emit('song-ended', self.s1, True)
        self.do()
        self.assertEquals(self.s1["~#playcount"], 0)
        self.assertEquals(self.s1["~#skipcount"], 0)

    def tearDown(self):
        self.w.destroy()
        config.quit()
class TInformation(TestCase):
    def setUp(self):
        quodlibet.config.init()
        self.library = SongLibrary()

    def test_none(self):
        Information(self.library, []).destroy()

    def test_one(self):
        f = AF({"~filename": "/dev/null"})
        Information(self.library, [f]).destroy()

    def test_two(self):
        f = AF({"~filename": "/dev/null"})
        f2 = AF({"~filename": "/dev/null2"})
        Information(self.library, [f, f2]).destroy()

    def test_album(self):
        f = AF({"~filename": "/dev/null", "album": "woo"})
        f2 = AF({"~filename": "/dev/null2", "album": "woo"})
        Information(self.library, [f, f2]).destroy()

    def test_artist(self):
        f = AF({"~filename": "/dev/null", "artist": "woo"})
        f2 = AF({"~filename": "/dev/null2", "artist": "woo"})
        Information(self.library, [f, f2]).destroy()

    def tearDown(self):
        self.library.destroy()
        quodlibet.config.quit()
Пример #4
0
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)
Пример #5
0
 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()
class TAudioFeeds(TestCase):
    def setUp(self):
        quodlibet.config.init()
        self.library = SongLibrary()
        self.bar = AudioFeeds(self.library, NullPlayer("fakesink"))

    def test_can_filter(self):
        for key in ["foo", "title", "fake~key", "~woobar", "~#huh"]:
            self.failIf(self.bar.can_filter(key))

    def tearDown(self):
        self.bar.destroy()
        self.library.destroy()
        quodlibet.config.quit()
Пример #7
0
class TPlaylists(TestCase):
    def setUp(self):
        quodlibet.config.init()
        self.library = SongLibrary()
        self.bar = PlaylistsBrowser(SongLibrary(), NullPlayer())

    def test_can_filter(self):
        for key in ["foo", "title", "fake~key", "~woobar", "~#huh"]:
            self.failIf(self.bar.can_filter(key))

    def tearDown(self):
        self.bar.destroy()
        self.library.destroy()
        quodlibet.config.quit()
Пример #8
0
class TPlaylists(TestCase):
    def setUp(self):
        quodlibet.config.init()
        self.library = SongLibrary()
        self.bar = PlaylistsBrowser(SongLibrary())

    def test_can_filter(self):
        for key in ["foo", "title", "fake~key", "~woobar", "~#huh"]:
            self.failIf(self.bar.can_filter(key))

    def tearDown(self):
        self.bar.destroy()
        self.library.destroy()
        quodlibet.config.quit()
Пример #9
0
class TLyricsPane(TestCase):

    def setUp(self):
        quodlibet.config.init()
        init_fake_app()
        self.pane = None
        self.library = SongLibrary()

    def tearDown(self):
        destroy_fake_app()
        self.library.destroy()
        quodlibet.config.quit()
        if self.pane:
            self.pane.destroy()

    def test_construction(self):
        af = AF({"~filename": fsnative(u"/dev/null")})
        self.pane = LyricsPane(af)

    def test_save_lyrics(self):
        af = self.temp_mp3()
        self.pane = LyricsPane(af)
        self.pane._save_lyrics(af, LYRICS)
        self.failUnlessEqual(af("~lyrics"), LYRICS)

    def test_save_encoded_lyrics(self):
        af = self.temp_mp3()
        self.pane = LyricsPane(af)
        self.pane._save_lyrics(af, LYRICS)
        self.failUnlessEqual(af("~lyrics"), LYRICS)

    def test_save_lyrics_deletes_lyric_file(self):
        af = self.temp_mp3()
        lf_name = af.lyric_filename
        os.makedirs(os.path.dirname(lf_name))
        with open(lf_name, "wb") as f:
            f.write(LYRICS.encode("utf-8"))
        self.failUnless(os.path.exists(lf_name))
        self.pane = LyricsPane(af)
        self.pane._save_lyrics(af, LYRICS)
        self.failIf(os.path.exists(lf_name))

    def temp_mp3(self):
        name = get_temp_copy(get_data_path('silence-44-s.mp3'))
        af = MP3File(name)
        af.sanitize()
        return af
Пример #10
0
class TInformation(TestCase):

    def setUp(self):
        quodlibet.config.init()
        init_fake_app()
        self.inf = None
        self.library = SongLibrary()

    def tearDown(self):
        destroy_fake_app()
        self.library.destroy()
        quodlibet.config.quit()
        if self.inf:
            self.inf.destroy()

    def test_none(self):
        Information(self.library, []).destroy()

    def test_one(self):
        f = AF({"~filename": fsnative(u"/dev/null")})
        self.inf = Information(self.library, [f])
        self.assert_child_is(OneSong)

    def test_two(self):
        f = AF({"~filename": fsnative(u"/dev/null")})
        f2 = AF({"~filename": fsnative(u"/dev/null2")})
        self.inf = Information(self.library, [f, f2])
        self.assert_child_is(ManySongs)

    def test_album(self):
        f = AF({"~filename": fsnative(u"/dev/null"), "album": "woo"})
        f2 = AF({"~filename": fsnative(u"/dev/null2"), "album": "woo"})
        self.inf = Information(self.library, [f, f2])
        self.assert_child_is(OneAlbum)

    def test_artist(self):
        f = AF({"~filename": fsnative(u"/dev/null"), "artist": "woo"})
        f2 = AF({"~filename": fsnative(u"/dev/null2"), "artist": "woo"})
        self.inf = Information(self.library, [f, f2])
        self.assert_child_is(OneArtist)

    def assert_child_is(self, cls):
        self.failUnless(isinstance(self.inf.get_child(), cls))
Пример #11
0
class TSongProperties(TestCase):
    af1 = AudioFile({"title": "woo"})
    af1.sanitize(fsnative(u"invalid"))
    af2 = AudioFile({"title": "bar", "album": "quux"})
    af2.sanitize(fsnative(u"alsoinvalid"))

    def setUp(self):
        SongProperties.plugins = DummyPlugins()
        config.init()
        self.library = SongLibrary()

    def test_onesong(self):
        self.window = SongProperties(self.library, [self.af1])

    def test_twosong(self):
        self.window = SongProperties(self.library, [self.af2, self.af1])

    def test_changed(self):
        self.test_twosong()
        self.window.hide()
        self.library.emit('changed', [self.af2])
        while Gtk.events_pending():
            Gtk.main_iteration()

    def test_removed(self):
        self.test_twosong()
        self.window.hide()
        self.library.emit('removed', [self.af2])
        while Gtk.events_pending():
            Gtk.main_iteration()

    def tearDown(self):
        try:
            self.window.destroy()
        except AttributeError:
            pass
        else:
            del(self.window)
        self.library.destroy()
        del(SongProperties.plugins)
        config.quit()
class TSongsMenuPlugins(TestCase):

    def _confirmer(self, *args):
        self.confirmed = True

    def setUp(self):
        self.tempdir = mkdtemp()
        self.pm = PluginManager(folders=[self.tempdir])
        self.confirmed = False
        self.handler = SongsMenuPluginHandler(self._confirmer, self._confirmer)
        self.pm.register_handler(self.handler)
        self.pm.rescan()
        self.assertEquals(self.pm.plugins, [])
        self.library = SongLibrary('foo')

    def tearDown(self):
        self.library.destroy()
        self.pm.quit()
        for f in os.listdir(self.tempdir):
            os.remove(os.path.join(self.tempdir, f))
        os.rmdir(self.tempdir)

    def create_plugin(self, id='', name='', desc='', icon='',
                      funcs=None, mod=False):
        fd, fn = mkstemp(suffix='.py', text=True, dir=self.tempdir)
        file = os.fdopen(fd, 'w')

        if mod:
            indent = ''
        else:
            file.write(
                "from quodlibet.plugins.songsmenu import SongsMenuPlugin\n")
            file.write("class %s(SongsMenuPlugin):\n" % name)
            indent = '    '
            file.write("%spass\n" % indent)

        if name:
            file.write("%sPLUGIN_ID = %r\n" % (indent, name))
        if name:
            file.write("%sPLUGIN_NAME = %r\n" % (indent, name))
        if desc:
            file.write("%sPLUGIN_DESC = %r\n" % (indent, desc))
        if icon:
            file.write("%sPLUGIN_ICON = %r\n" % (indent, icon))
        for f in (funcs or []):
            if f in ["__init__"]:
                file.write("%sdef %s(self, *args): super(%s, self).__init__("
                           "*args); raise Exception(\"as expected\")\n"
                           % (indent, f, name))
            else:
                file.write("%sdef %s(*args): return args\n" % (indent, f))
        file.flush()
        file.close()

    def test_empty_has_no_plugins(self):
        self.pm.rescan()
        self.assertEquals(self.pm.plugins, [])

    def test_name_and_desc_plus_func_is_one(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_song'])
        self.pm.rescan()
        self.assertEquals(len(self.pm.plugins), 1)

    def test_additional_functions_still_only_one(self):
        self.create_plugin(name='Name', desc='Desc',
                funcs=['plugin_song', 'plugin_songs'])
        self.pm.rescan()
        self.assertEquals(len(self.pm.plugins), 1)

    def test_two_plugins_are_two(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_song'])
        self.create_plugin(name='Name2', desc='Desc2',
                funcs=['plugin_albums'])
        self.pm.rescan()
        self.assertEquals(len(self.pm.plugins), 2)

    def test_disables_plugin(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_song'])
        self.pm.rescan()
        self.failIf(self.pm.enabled(self.pm.plugins[0]))

    def test_enabledisable_plugin(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_song'])
        self.pm.rescan()
        plug = self.pm.plugins[0]
        self.pm.enable(plug, True)
        self.failUnless(self.pm.enabled(plug))
        self.pm.enable(plug, False)
        self.failIf(self.pm.enabled(plug))

    def test_ignores_broken_plugin(self):
        self.create_plugin(name="Broken", desc="Desc",
                           funcs=["__init__", "plugin_song"])
        self.pm.rescan()
        plug = self.pm.plugins[0]
        self.pm.enable(plug, True)
        with capture_output():
            menu = self.handler.Menu(None, [AudioFile()])
        self.failIf(menu and menu.get_children())

    def test_Menu(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_song'])
        self.handler.Menu(None, [AudioFile()])

    def test_handling_songs_without_confirmation(self):
        plugin = Plugin(FakeSongsMenuPlugin)
        self.handler.plugin_enable(plugin)
        MAX = FakeSongsMenuPlugin.MAX_INVOCATIONS
        songs = [AudioFile({'~filename': "/tmp/%s" % x, 'artist': 'foo'})
                 for x in range(MAX)]
        self.handler.handle(plugin.id, self.library, None, songs)
        self.failIf(self.confirmed, ("Wasn't expecting a confirmation for %d"
                                     " invocations" % len(songs)))

    def test_handling_lots_of_songs_with_confirmation(self):
        plugin = Plugin(FakeSongsMenuPlugin)
        self.handler.plugin_enable(plugin)
        MAX = FakeSongsMenuPlugin.MAX_INVOCATIONS
        songs = [AudioFile({'~filename': "/tmp/%s" % x, 'artist': 'foo'})
                 for x in range(MAX + 1)]
        self.handler.handle(plugin.id, self.library, None, songs)
        self.failUnless(self.confirmed,
                        ("Should have confirmed %d invocations (Max=%d)."
                         % (len(songs), MAX)))
Пример #13
0
class TSongsMenu(TestCase):
    def setUp(self):
        config.init()
        self.library = SongLibrary()
        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(text_type(song["title"])))

    def test_empty(self):
        self.menu = SongsMenu(self.library, self.songs, plugins=False,
                              playlists=False, queue=False,
                              remove=False, delete=False, edit=False,
                              ratings=False)
        self.failUnlessEqual(0, len(self.menu))

    def test_simple(self):
        self.menu = SongsMenu(self.library, self.songs, plugins=False)

    def test_playlists(self):
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=True,
            queue=False, remove=False, delete=False, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].can_add = False
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=True,
            queue=False, remove=False, delete=False, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_queue(self):
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=False,
            queue=True, remove=False, delete=False, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].can_add = False
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=False,
            queue=True, remove=False, delete=False, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_remove(self):
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=False,
            queue=False, remove=True, delete=False, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_remove_sensitive(self):
        self.library.add(self.songs)
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=False,
            queue=False, remove=True, delete=False, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

    def test_delete(self):
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=False,
            queue=False, remove=False, delete=True, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].is_file = False
        self.menu = SongsMenu(
            self.library, self.songs, plugins=False, playlists=False,
            queue=False, remove=False, delete=True, edit=False,
            ratings=False)
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def tearDown(self):
        self.device.destroy()
        self.library.destroy()
        try:
            self.menu.destroy()
        except AttributeError:
            pass
        else:
            del(self.menu)
        config.quit()
Пример #14
0
class TSongsMenu(TestCase):
    def setUp(self):
        self.library = SongLibrary()
        quodlibet.player.init("nullbe")
        self.device = quodlibet.player.init_device(self.library)

        self.songs = [AudioFile({"title": x}) for x in ["song1", "song2", "song3"]]
        for song in self.songs:
            song.sanitize(song["title"])

    def test_empty(self):
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=False,
            devices=False,
            remove=False,
            delete=False,
            edit=False,
        )
        self.failUnlessEqual(0, len(self.menu))

    def test_simple(self):
        self.menu = SongsMenu(self.library, self.songs, plugins=False)

    def test_playlists(self):
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=True,
            queue=False,
            devices=False,
            remove=False,
            delete=False,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].can_add = False
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=True,
            queue=False,
            devices=False,
            remove=False,
            delete=False,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_queue(self):
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=True,
            devices=False,
            remove=False,
            delete=False,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].can_add = False
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=True,
            devices=False,
            remove=False,
            delete=False,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_devices(self):
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=False,
            devices=True,
            remove=False,
            delete=False,
            edit=False,
        )
        from quodlibet import browsers

        if browsers.media.MediaDevices in browsers.browsers:
            self.failUnlessEqual(1, len(self.menu))
        else:
            self.failUnlessEqual(0, len(self.menu))

    def test_remove(self):
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=False,
            devices=False,
            remove=True,
            delete=False,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_remove_sensitive(self):
        self.library.add(self.songs)
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=False,
            devices=False,
            remove=True,
            delete=False,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

    def test_delete(self):
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=False,
            devices=False,
            remove=False,
            delete=True,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].is_file = False
        self.menu = SongsMenu(
            self.library,
            self.songs,
            plugins=False,
            playlists=False,
            queue=False,
            devices=False,
            remove=False,
            delete=True,
            edit=False,
        )
        self.failUnlessEqual(1, len(self.menu))
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def tearDown(self):
        quodlibet.player.quit(self.device)
        self.library.destroy()
        try:
            self.menu.destroy()
        except AttributeError:
            pass
        else:
            del (self.menu)
Пример #15
0
class TPlaylistPlugins(TestCase):

    class MockBrowser(Browser):
        def __init__(self):
            super(TPlaylistPlugins.MockBrowser, self).__init__()
            self.activated = False

        def activate(self):
            self.activated = True

        def get_toplevel(self):
            return self

        def is_toplevel(self):
            return True

    def _confirmer(self, *args):
        self.confirmed = True

    def setUp(self):
        self.tempdir = mkdtemp()
        self.pm = PluginManager(folders=[self.tempdir])
        self.confirmed = False
        self.mock_browser = self.MockBrowser()
        self.handler = PlaylistPluginHandler(self._confirmer)
        self.pm.register_handler(self.handler)
        self.pm.rescan()
        self.assertEquals(self.pm.plugins, [])
        self.library = SongLibrary('foo')

    def tearDown(self):
        self.library.destroy()
        self.pm.quit()
        shutil.rmtree(self.tempdir)

    def create_plugin(self, id='', name='', desc='', icon='',
                      funcs=None, mod=False):
        fd, fn = mkstemp(suffix='.py', text=True, dir=self.tempdir)
        file = os.fdopen(fd, 'w')

        if mod:
            indent = ''
        else:
            file.write(
                "from quodlibet.plugins.playlist import PlaylistPlugin\n")
            file.write("class %s(PlaylistPlugin):\n" % name)
            indent = '    '
            file.write("%spass\n" % indent)

        if name:
            file.write("%sPLUGIN_ID = %r\n" % (indent, name))
        if name:
            file.write("%sPLUGIN_NAME = %r\n" % (indent, name))
        if desc:
            file.write("%sPLUGIN_DESC = %r\n" % (indent, desc))
        if icon:
            file.write("%sPLUGIN_ICON = %r\n" % (indent, icon))
        for f in (funcs or []):
            if f in ["__init__"]:
                file.write("%sdef %s(self, *args): super(%s, self).__init__("
                           "*args); raise Exception(\"as expected.\")\n"
                           % (indent, f, name))
            else:
                file.write("%sdef %s(*args): return args\n" % (indent, f))
        file.flush()
        file.close()

    def test_empty_has_no_plugins(self):
        self.pm.rescan()
        self.assertEquals(self.pm.plugins, [])

    def test_name_and_desc_plus_func_is_one(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_playlist'])
        self.pm.rescan()
        self.assertEquals(len(self.pm.plugins), 1)

    def test_additional_functions_still_only_one(self):
        self.create_plugin(name='Name', desc='Desc',
                           funcs=['plugin_playlist', 'plugin_playlists'])
        self.pm.rescan()
        self.assertEquals(len(self.pm.plugins), 1)

    def test_two_plugins_are_two(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_playlist'])
        self.create_plugin(name='Name2', desc='Desc2',
                           funcs=['plugin_albums'])
        self.pm.rescan()
        self.assertEquals(len(self.pm.plugins), 2)

    def test_disables_plugin(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_playlist'])
        self.pm.rescan()
        self.failIf(self.pm.enabled(self.pm.plugins[0]))

    def test_enabledisable_plugin(self):
        self.create_plugin(name='Name', desc='Desc', funcs=['plugin_playlist'])
        self.pm.rescan()
        plug = self.pm.plugins[0]
        self.pm.enable(plug, True)
        self.failUnless(self.pm.enabled(plug))
        self.pm.enable(plug, False)
        self.failIf(self.pm.enabled(plug))

    def test_ignores_broken_plugin(self):
        self.create_plugin(name="Broken", desc="Desc",
                           funcs=["__init__", "plugin_playlist"])

        self.pm.rescan()
        plug = self.pm.plugins[0]
        self.pm.enable(plug, True)
        menu = Gtk.Menu()
        with capture_output():
            self.handler.populate_menu(menu, None, self.mock_browser,
                                       [TEST_PLAYLIST])
        self.failUnlessEqual(len(menu.get_children()), 0,
                             msg="Shouldn't have enabled a broken plugin")

    def test_populate_menu(self):
        plugin = Plugin(FakePlaylistPlugin)
        self.handler.plugin_enable(plugin)
        menu = Gtk.Menu()
        self.handler.populate_menu(menu, None, self.mock_browser,
                                   [TEST_PLAYLIST])
        # Don't forget the separator
        num = len(menu.get_children()) - 1
        self.failUnlessEqual(num, 1, msg="Need 1 plugin not %d" % num)

    def test_handling_playlists_without_confirmation(self):
        plugin = Plugin(FakePlaylistPlugin)
        self.handler.plugin_enable(plugin)
        playlists = generate_playlists(MAX_PLAYLISTS)
        self.handler.handle(plugin.id, self.library, self.mock_browser,
                            playlists)
        self.failUnless("Didn't execute plugin",
                        FakePlaylistPlugin.total > 0)
        self.failIf(self.confirmed, ("Wasn't expecting a confirmation for %d"
                                     " invocations" % len(playlists)))

    def test_handling_lots_of_songs_with_confirmation(self):
        plugin = Plugin(FakePlaylistPlugin)
        self.handler.plugin_enable(plugin)
        playlists = generate_playlists(MAX_PLAYLISTS + 1)
        self.handler.handle(plugin.id, self.library, self.mock_browser,
                            playlists)
        self.failUnless(self.confirmed,
                        ("Should have confirmed %d invocations (Max=%d)."
                         % (len(playlists), MAX_PLAYLISTS)))
Пример #16
0
class TSongsMenu(TestCase):

    def _confirmer(self, *args):
        self.confirmed = True
        return False

    def setUp(self):
        config.init()
        self.library = SongLibrary()
        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(text_type(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 = [RemoteFile("http://example.com/")]
        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 empty_menu_with(self, plugins=False, playlists=False, queue=False,
                        remove=False, delete=False, edit=False, ratings=False,
                        show_files=False, removal_confirmer=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)

    def tearDown(self):
        self.device.destroy()
        self.library.destroy()
        try:
            self.menu.destroy()
        except AttributeError:
            pass
        else:
            del(self.menu)
        config.quit()