async def test_playlist_exit_fm_mode(app_mock, song, mocker): mocker.patch.object(Playlist, 'a_set_current_song') pl = Playlist(app_mock) pl.mode = PlaylistMode.fm pl.current_song = song assert pl.mode is PlaylistMode.normal assert app_mock.task_mgr.get_or_create.called
async def test_reactivate_fm_mode_after_playing_other_songs( event_loop, app_mock, song, song1, mocker): def f(*args, **kwargs): return [song1] def is_active(fm): return fm.is_active playlist = Playlist(app_mock) app_mock.playlist = playlist app_mock.task_mgr = TaskManager(app_mock, event_loop) fm = FM(app_mock) fm.activate(f) assert playlist.mode is PlaylistMode.fm await asyncio.sleep(0.1) # wait for fm-fetch-song task finished # user trigger play next app_mock.playlist.current_song = song assert playlist.mode is PlaylistMode.normal assert is_active(fm) is False await asyncio.sleep(0.1) # wait for validate-song task finished assert playlist.list() == [song] fm.activate(f) assert is_active(fm) is True assert playlist.mode is PlaylistMode.fm
async def test_playlist_exit_fm_mode(app_mock, song, mocker, mock_a_set_cursong): pl = Playlist(app_mock) pl.mode = PlaylistMode.fm pl.current_song = song assert pl.mode is PlaylistMode.normal assert app_mock.task_mgr.get_or_create.called
def test_play_all(app_mock): player = Player() playlist = Playlist(app_mock) player.set_playlist(playlist) playlist.mode = PlaylistMode.fm playlist.set_models([], next_=True) assert playlist.mode == PlaylistMode.normal
async def test_playlist_change_mode(app_mock, mocker): # from normal to fm pl = Playlist(app_mock) pl.mode = PlaylistMode.fm assert pl.playback_mode is PlaybackMode.sequential # from fm to normal pl.mode = PlaylistMode.normal assert pl.mode is PlaylistMode.normal
def test_playlist_next_should_call_set_current_song(app_mock, mocker, song): mock_set_current_song = mocker.patch.object(Playlist, 'set_current_song') pl = Playlist(app_mock) pl.add(song) task = pl.next() # Next method should call set_current_song and return an asyncio task. # Since it is complex to mock and return a asyncio.Task, we do not # check the type of task object. assert task is not None assert mock_set_current_song.called
class TestPlaylist(TestCase): def setUp(self): self.s1 = FakeSongModel() self.s2 = FakeSongModel() self.playlist = Playlist(app_mock) self.playlist.add(self.s1) self.playlist.add(self.s2) def tearDown(self): self.playlist.clear() def test_add(self): self.playlist.add(self.s1) self.assertEqual(len(self.playlist), 2) def test_getitem(self): self.assertEqual(self.playlist[1], self.s2) def test_mark_as_bad(self): self.assertEqual(self.playlist.next_song, self.s1) self.playlist.mark_as_bad(self.s1) self.assertEqual(self.playlist.next_song, self.s2) def test_list(self): self.assertIn(self.s1, self.playlist.list())
async def test_playlist_change_mode(app_mock, mocker): mock_clear = mocker.patch.object(Playlist, 'clear') # from normal to fm pl = Playlist(app_mock) pl.mode = PlaylistMode.fm mock_clear.assert_called_once_with() assert pl.playback_mode is PlaybackMode.sequential # from fm to normal pl.mode = PlaylistMode.normal assert pl.mode is PlaylistMode.normal
async def test_playlist_fm_mode_play_previous(app_mock, song, song1, mocker): pl = Playlist(app_mock) pl.mode = PlaylistMode.fm pl.fm_add(song1) pl.fm_add(song) pl._current_song = song pl.current_song = song1 # should not exit fm mode assert pl.mode is PlaylistMode.fm
async def test_playlist_fm_mode_play_next(app_mock, song, song1, mocker): mocker.patch.object(Playlist, 'a_set_current_song') pl = Playlist(app_mock) pl.mode = PlaylistMode.fm pl.fm_add(song1) pl.fm_add(song) pl._current_song = song1 pl.current_song = song # should not exit fm mode assert pl.mode is PlaylistMode.fm
async def test_playlist_fm_mode_play_next(app_mock, song, song1, mock_a_set_cursong): pl = Playlist(app_mock) pl.mode = PlaylistMode.fm pl.fm_add(song1) pl.fm_add(song) pl._current_song = song1 pl.current_song = song # should not exit fm mode assert pl.mode is PlaylistMode.fm
async def test_playlist_resumed_from_eof_reached(app_mock, song, mocker, mock_a_set_cursong): mock_set_current_song = mocker.patch.object(Playlist, 'set_current_song') pl = Playlist(app_mock) def feed_playlist(): pl.fm_add(song) pl.next() pl.eof_reached.connect(feed_playlist) pl.mode = PlaylistMode.fm pl.next() mock_set_current_song.assert_has_calls([mock.call(song)])
async def test_playlist_eof_reached(app_mock, song, mocker): mock_emit = mocker.patch.object(Signal, 'emit') pl = Playlist(app_mock) pl.mode = PlaylistMode.fm pl.next() # first emit pl.fm_add(song) # assume current_song is song pl._current_song = song pl.next() # second emit mock_emit.assert_has_calls([ mock.call(), mock.call(), ])
async def test_playlist_resumed_from_eof_reached(app_mock, song, mocker): mock_current_song = mocker.patch.object(Playlist, 'current_song') mock_set = mocker.MagicMock() mock_current_song.__get__ = mocker.MagicMock(return_value=None) mock_current_song.__set__ = mock_set pl = Playlist(app_mock) def feed_playlist(): pl.fm_add(song) pl.next() pl.eof_reached.connect(feed_playlist) pl.mode = PlaylistMode.fm pl.next() mock_set.assert_has_calls([mock.call(pl, song)])
def test_when_playlist_fm_mode_exited(app_mock, song, mocker): mock_fetch = mocker.MagicMock() app_mock.playlist = Playlist(app_mock) fm = FM(app_mock) fm.activate(mock_fetch) app_mock.playlist.mode = PlaylistMode.normal assert fm._activated is False # noqa
def __init__(self, args, config): self.mode = config.MODE # DEPRECATED: use app.config.MODE instead self.config = config self.args = args self.initialized = Signal() self.about_to_shutdown = Signal() self.plugin_mgr = PluginsManager(self) self.request = Request() # TODO: rename request to http self.version_mgr = VersionManager(self) self.task_mgr = TaskManager(self) # Library. self.library = Library(config.PROVIDERS_STANDBY) # TODO: initialization should be moved into initialize Resolver.library = self.library # Player. self.player = Player( audio_device=bytes(config.MPV_AUDIO_DEVICE, 'utf-8')) self.playlist = Playlist( self, audio_select_policy=config.AUDIO_SELECT_POLICY) self.live_lyric = LiveLyric(self) self.fm = FM(self) # TODO: initialization should be moved into initialize self.player.set_playlist(self.playlist) self.about_to_shutdown.connect(lambda _: self.dump_state(), weak=False)
async def test_prepare_media_in_non_mainthread(app_mock, song): pl = Playlist(app_mock) loop = asyncio.get_event_loop() try: await loop.run_in_executor(None, pl.prepare_media, song) except RuntimeError: pytest.fail('Prepare media in non mainthread should work')
async def test_playlist_eof_reached(app_mock, song, mocker, mock_a_set_cursong): mock_emit = mocker.patch.object(Signal, 'emit') pl = Playlist(app_mock) pl.mode = PlaylistMode.fm pl.next() # first emit pl.fm_add(song) # assume current_song is song pl._current_song = song pl.next() # second emit mock_emit.assert_has_calls([ mock.call(PlaybackMode.sequential), mock.call(PlaylistMode.fm), mock.call(), mock.call(0, 1), # songs_added mock.call() ])
def test_change_song(app_mock, mocker, song, song1): mocker.patch.object(Player, 'play') pl = Playlist(app_mock) pl.add(song) pl._current_song = song player = Player() player.set_playlist(pl) with mock.patch.object(Playlist, 'current_song', new_callable=mock.PropertyMock) as mock_s: mock_s.return_value = song # return current song pl.set_current_song(song1) pl.next() assert pl.current_song == song
def mpvplayer(): player = MpvPlayer(Playlist(app_mock)) player.volume = 0 yield player player.stop() # HELP: player.shutdown() causes error on Windows # Windows fatal exception: code 0xe24c4a02 # Ref: https://github.com/feeluown/FeelUOwn/runs/4996179558 player.shutdown()
def attach_attrs(app): """初始化 app 属性""" loop = asyncio.get_event_loop() app.library = Library(app.config.PROVIDERS_STANDBY) app.live_lyric = LiveLyric(app) player_kwargs = dict( audio_device=bytes(app.config.MPV_AUDIO_DEVICE, 'utf-8')) app.playlist = Playlist(app, audio_select_policy=app.config.AUDIO_SELECT_POLICY) app.player = Player(app.playlist, **(player_kwargs or {})) app.plugin_mgr = PluginsManager(app) app.request = Request() app.task_mgr = TaskManager(app, loop) app.fm = FM(app) if app.mode & (app.DaemonMode | app.GuiMode): app.version_mgr = VersionManager(app) if app.mode & app.DaemonMode: app.server = FuoServer(app) app.pubsub_gateway = PubsubGateway() app._ll_publisher = LiveLyricPublisher(app.pubsub_gateway) if app.mode & app.GuiMode: from feeluown.uimodels.provider import ProviderUiManager from feeluown.uimodels.playlist import PlaylistUiManager from feeluown.uimodels.my_music import MyMusicUiManager from feeluown.uimodels.collection import CollectionUiManager from feeluown.collection import CollectionManager from .gui.browser import Browser from .gui.hotkey import HotkeyManager from .gui.image import ImgManager from .gui.theme import ThemeManager from .gui.tips import TipsManager from .gui.ui import Ui from .gui.tray import Tray # GUI 的一些辅助管理模块 app.coll_mgr = CollectionManager(app) app.theme_mgr = ThemeManager(app) app.tips_mgr = TipsManager(app) app.hotkey_mgr = HotkeyManager(app) app.img_mgr = ImgManager(app) # GUI 组件的数据管理模块 app.pvd_uimgr = ProviderUiManager(app) app.pl_uimgr = PlaylistUiManager(app) app.mymusic_uimgr = MyMusicUiManager(app) app.coll_uimgr = CollectionUiManager(app) app.browser = Browser(app) app.ui = Ui(app) if app.config.ENABLE_TRAY: app.tray = Tray(app) app.show_msg = app.ui.toolbar.status_line.get_item( 'notify').widget.show_msg
async def test_fetch_song_cancelled(event_loop, app_mock, song, mocker): mock_fetch = mocker.MagicMock() app_mock.playlist = Playlist(app_mock) app_mock.task_mgr = TaskManager(app_mock, event_loop) fm = FM(app_mock) fm.activate(mock_fetch) task_spec = app_mock.task_mgr.get_or_create(fm._fetch_songs_task_name) task_spec._task.cancel() await asyncio.sleep(0.1) # schedule cancel callback assert fm._is_fetching_songs is False
def test_fm_activate_and_deactivate(app_mock, song, mocker): mock_fetch = mocker.MagicMock(return_value=[song]) app_mock.playlist = Playlist(app_mock) fm = FM(app_mock) fm.activate(mock_fetch) assert app_mock.playlist.mode is PlaylistMode.fm assert app_mock.task_mgr.get_or_create.called fm.deactivate() assert app_mock.playlist.mode is PlaylistMode.normal
def pl(app_mock, song, song1): """ pl: [song, song1], current_song: song """ playlist = Playlist(app_mock) playlist.add(song) playlist.add(song1) playlist._current_song = song return playlist
def test_serialize_app(mocker): app = mocker.Mock(spec=App) app.live_lyric = mocker.Mock() app.live_lyric.current_sentence = '' player = Player(Playlist(app)) app.player = player app.playlist = player.playlist for format in ('plain', 'json'): serialize(format, app, brief=False) serialize(format, app, fetch=True) player.shutdown()
async def test_fetch_song_failed(event_loop, app_mock, song, mocker): mock_fetch = mocker.MagicMock(side_effect=ProviderIOError) mock_fm_add = mocker.patch.object(Playlist, 'fm_add') app_mock.playlist = Playlist(app_mock) app_mock.task_mgr = TaskManager(app_mock, event_loop) fm = FM(app_mock) fm.activate(mock_fetch) assert fm._is_fetching_songs is True await asyncio.sleep(0.1) # schedule mock_fetch callback assert fm._is_fetching_songs is False assert not mock_fm_add.called
class TestPlayerAndPlaylist(TestCase): def setUp(self): self.playlist = Playlist(app_mock) self.player = MpvPlayer() self.player.set_playlist(self.player) def tearDown(self): self.player.stop() self.player.shutdown() @skipIf(cannot_play_audio, '') @mock.patch.object(MpvPlayer, 'play') def test_remove_current_song_2(self, mock_play): """当播放列表只有一首歌时,移除它""" s1 = FakeValidSongModel() self.playlist.current_song = s1 time.sleep(MPV_SLEEP_SECOND) # 让 Mpv 真正的开始播放 self.playlist.remove(s1) self.assertEqual(len(self.playlist), 0) self.assertEqual(self.player.state, State.stopped)
async def test_multiple_eof_reached_signal(event_loop, app_mock, song, mocker): mock_fetch = mocker.MagicMock(return_value=[song] * 3) mock_fm_add = mocker.patch.object(Playlist, 'fm_add') app_mock.playlist = Playlist(app_mock) app_mock.task_mgr = TaskManager(app_mock, event_loop) fm = FM(app_mock) fm.activate(mock_fetch) app_mock.playlist.next() app_mock.playlist.next() task_spec = app_mock.task_mgr.get_or_create(fm._fetch_songs_task_name) await task_spec._task # this is a little bit tricky # called exactly once mock_fetch.assert_called_once_with(3) assert mock_fm_add.called
async def test_set_cursong_in_non_mainthread(app_mock, song): pl = Playlist(app_mock) def set_in_non_mainthread(): pl.current_song = song loop = asyncio.get_event_loop() try: # make song url invalid song.url = '' # playlist should create a asyncio task to fetch a standby # set current song in non mainthread await loop.run_in_executor(None, set_in_non_mainthread) except RuntimeError: pytest.fail('Set current song in non mainthread should work')
async def test_play_next_bad_song(app_mock, song, song1, mocker): """ Prepare media for song raises unknown error, the song should be marked as bad. """ pl = Playlist(app_mock) mocker.patch.object(pl, '_prepare_media', side_effect=Exception()) mock_mark_as_bad = mocker.patch.object(pl, 'mark_as_bad') mock_next = mocker.patch.object(pl, 'next') pl.add(song) pl.add(song1) pl._current_song = song await pl.a_set_current_song(pl.next_song) assert mock_mark_as_bad.called assert mock_next.called