From 3c53c1ddcd51e6c8de91f1c64bb5ce74e19e571c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 11 Oct 2013 22:17:27 +0200 Subject: [PATCH] tests: Merge BaseBackend and LocalBackend tests --- tests/backends/base/__init__.py | 11 - tests/backends/base/events.py | 26 - tests/backends/base/library.py | 202 ------ tests/backends/base/playback.py | 876 ------------------------- tests/backends/base/playlists.py | 102 --- tests/backends/base/tracklist.py | 295 --------- tests/backends/local/__init__.py | 13 +- tests/backends/local/events_test.py | 24 +- tests/backends/local/library_test.py | 201 +++++- tests/backends/local/playback_test.py | 870 +++++++++++++++++++++++- tests/backends/local/playlists_test.py | 99 ++- tests/backends/local/tracklist_test.py | 292 ++++++++- 12 files changed, 1475 insertions(+), 1536 deletions(-) delete mode 100644 tests/backends/base/__init__.py delete mode 100644 tests/backends/base/events.py delete mode 100644 tests/backends/base/library.py delete mode 100644 tests/backends/base/playback.py delete mode 100644 tests/backends/base/playlists.py delete mode 100644 tests/backends/base/tracklist.py diff --git a/tests/backends/base/__init__.py b/tests/backends/base/__init__.py deleted file mode 100644 index 7dc4bcf6c4..0000000000 --- a/tests/backends/base/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals - - -def populate_tracklist(func): - def wrapper(self): - self.tl_tracks = self.core.tracklist.add(self.tracks) - return func(self) - - wrapper.__name__ = func.__name__ - wrapper.__doc__ = func.__doc__ - return wrapper diff --git a/tests/backends/base/events.py b/tests/backends/base/events.py deleted file mode 100644 index a5d9fa7b87..0000000000 --- a/tests/backends/base/events.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import unicode_literals - -import mock -import pykka - -from mopidy import core, audio -from mopidy.backends import listener - - -@mock.patch.object(listener.BackendListener, 'send') -class BackendEventsTest(object): - config = {} - - def setUp(self): - self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start( - config=self.config, audio=self.audio).proxy() - self.core = core.Core.start(backends=[self.backend]).proxy() - - def tearDown(self): - pykka.ActorRegistry.stop_all() - - def test_playlists_refresh_sends_playlists_loaded_event(self, send): - send.reset_mock() - self.core.playlists.refresh().get() - self.assertEqual(send.call_args[0][0], 'playlists_loaded') diff --git a/tests/backends/base/library.py b/tests/backends/base/library.py deleted file mode 100644 index 23c76f38ee..0000000000 --- a/tests/backends/base/library.py +++ /dev/null @@ -1,202 +0,0 @@ -from __future__ import unicode_literals - -import unittest - -import pykka - -from mopidy import core -from mopidy.models import Track, Album, Artist - - -class LibraryControllerTest(object): - artists = [Artist(name='artist1'), Artist(name='artist2'), Artist()] - albums = [ - Album(name='album1', artists=artists[:1]), - Album(name='album2', artists=artists[1:2]), - Album()] - tracks = [ - Track(uri='local:track:path1', name='track1', artists=artists[:1], - album=albums[0], date='2001-02-03', length=4000), - Track(uri='local:track:path2', name='track2', artists=artists[1:2], - album=albums[1], date='2002', length=4000), - Track()] - config = {} - - def setUp(self): - self.backend = self.backend_class.start( - config=self.config, audio=None).proxy() - self.core = core.Core(backends=[self.backend]) - self.library = self.core.library - - def tearDown(self): - pykka.ActorRegistry.stop_all() - - def test_refresh(self): - self.library.refresh() - - @unittest.SkipTest - def test_refresh_uri(self): - pass - - @unittest.SkipTest - def test_refresh_missing_uri(self): - pass - - def test_lookup(self): - tracks = self.library.lookup(self.tracks[0].uri) - self.assertEqual(tracks, self.tracks[0:1]) - - def test_lookup_unknown_track(self): - tracks = self.library.lookup('fake uri') - self.assertEqual(tracks, []) - - def test_find_exact_no_hits(self): - result = self.library.find_exact(track=['unknown track']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.find_exact(artist=['unknown artist']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.find_exact(album=['unknown artist']) - self.assertEqual(list(result[0].tracks), []) - - def test_find_exact_uri(self): - track_1_uri = 'local:track:path1' - result = self.library.find_exact(uri=track_1_uri) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - track_2_uri = 'local:track:path2' - result = self.library.find_exact(uri=track_2_uri) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_find_exact_track(self): - result = self.library.find_exact(track=['track1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.find_exact(track=['track2']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_find_exact_artist(self): - result = self.library.find_exact(artist=['artist1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.find_exact(artist=['artist2']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_find_exact_album(self): - result = self.library.find_exact(album=['album1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.find_exact(album=['album2']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_find_exact_date(self): - result = self.library.find_exact(date=['2001']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.find_exact(date=['2001-02-03']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.find_exact(date=['2002']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_find_exact_wrong_type(self): - test = lambda: self.library.find_exact(wrong=['test']) - self.assertRaises(LookupError, test) - - def test_find_exact_with_empty_query(self): - test = lambda: self.library.find_exact(artist=['']) - self.assertRaises(LookupError, test) - - test = lambda: self.library.find_exact(track=['']) - self.assertRaises(LookupError, test) - - test = lambda: self.library.find_exact(album=['']) - self.assertRaises(LookupError, test) - - def test_search_no_hits(self): - result = self.library.search(track=['unknown track']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.search(artist=['unknown artist']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.search(album=['unknown artist']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.search(uri=['unknown']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.search(any=['unknown']) - self.assertEqual(list(result[0].tracks), []) - - def test_search_uri(self): - result = self.library.search(uri=['TH1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.search(uri=['TH2']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_search_track(self): - result = self.library.search(track=['Rack1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.search(track=['Rack2']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_search_artist(self): - result = self.library.search(artist=['Tist1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.search(artist=['Tist2']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_search_album(self): - result = self.library.search(album=['Bum1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.search(album=['Bum2']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_search_date(self): - result = self.library.search(date=['2001']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.search(date=['2001-02-03']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - result = self.library.search(date=['2001-02-04']) - self.assertEqual(list(result[0].tracks), []) - - result = self.library.search(date=['2002']) - self.assertEqual(list(result[0].tracks), self.tracks[1:2]) - - def test_search_any(self): - result = self.library.search(any=['Tist1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - result = self.library.search(any=['Rack1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - result = self.library.search(any=['Bum1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - result = self.library.search(any=['TH1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) - - def test_search_wrong_type(self): - test = lambda: self.library.search(wrong=['test']) - self.assertRaises(LookupError, test) - - def test_search_with_empty_query(self): - test = lambda: self.library.search(artist=['']) - self.assertRaises(LookupError, test) - - test = lambda: self.library.search(track=['']) - self.assertRaises(LookupError, test) - - test = lambda: self.library.search(album=['']) - self.assertRaises(LookupError, test) - - test = lambda: self.library.search(uri=['']) - self.assertRaises(LookupError, test) - - test = lambda: self.library.search(any=['']) - self.assertRaises(LookupError, test) diff --git a/tests/backends/base/playback.py b/tests/backends/base/playback.py deleted file mode 100644 index 44ae40f95e..0000000000 --- a/tests/backends/base/playback.py +++ /dev/null @@ -1,876 +0,0 @@ -from __future__ import unicode_literals - -import mock -import random -import time -import unittest - -import pykka - -from mopidy import audio, core -from mopidy.core import PlaybackState -from mopidy.models import Track - -from tests.backends.base import populate_tracklist - -# TODO Test 'playlist repeat', e.g. repeat=1,single=0 - - -class PlaybackControllerTest(object): - tracks = [] - config = {} - - def setUp(self): - self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start( - config=self.config, audio=self.audio).proxy() - self.core = core.Core(backends=[self.backend]) - self.playback = self.core.playback - self.tracklist = self.core.tracklist - - assert len(self.tracks) >= 3, \ - 'Need at least three tracks to run tests.' - assert self.tracks[0].length >= 2000, \ - 'First song needs to be at least 2000 miliseconds' - - def tearDown(self): - pykka.ActorRegistry.stop_all() - - def test_initial_state_is_stopped(self): - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - def test_play_with_empty_playlist(self): - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - def test_play_with_empty_playlist_return_value(self): - self.assertEqual(self.playback.play(), None) - - @populate_tracklist - def test_play_state(self): - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @populate_tracklist - def test_play_return_value(self): - self.assertEqual(self.playback.play(), None) - - @populate_tracklist - def test_play_track_state(self): - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.playback.play(self.tracklist.tl_tracks[-1]) - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @populate_tracklist - def test_play_track_return_value(self): - self.assertEqual(self.playback.play( - self.tracklist.tl_tracks[-1]), None) - - @populate_tracklist - def test_play_when_playing(self): - self.playback.play() - track = self.playback.current_track - self.playback.play() - self.assertEqual(track, self.playback.current_track) - - @populate_tracklist - def test_play_when_paused(self): - self.playback.play() - track = self.playback.current_track - self.playback.pause() - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(track, self.playback.current_track) - - @populate_tracklist - def test_play_when_pause_after_next(self): - self.playback.play() - self.playback.next() - self.playback.next() - track = self.playback.current_track - self.playback.pause() - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(track, self.playback.current_track) - - @populate_tracklist - def test_play_sets_current_track(self): - self.playback.play() - self.assertEqual(self.playback.current_track, self.tracks[0]) - - @populate_tracklist - def test_play_track_sets_current_track(self): - self.playback.play(self.tracklist.tl_tracks[-1]) - self.assertEqual(self.playback.current_track, self.tracks[-1]) - - @populate_tracklist - def test_play_skips_to_next_track_on_failure(self): - # If backend's play() returns False, it is a failure. - self.backend.playback.play = lambda track: track != self.tracks[0] - self.playback.play() - self.assertNotEqual(self.playback.current_track, self.tracks[0]) - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_current_track_after_completed_playlist(self): - self.playback.play(self.tracklist.tl_tracks[-1]) - self.playback.on_end_of_track() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.assertEqual(self.playback.current_track, None) - - self.playback.play(self.tracklist.tl_tracks[-1]) - self.playback.next() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.assertEqual(self.playback.current_track, None) - - @populate_tracklist - def test_previous(self): - self.playback.play() - self.playback.next() - self.playback.previous() - self.assertEqual(self.playback.current_track, self.tracks[0]) - - @populate_tracklist - def test_previous_more(self): - self.playback.play() # At track 0 - self.playback.next() # At track 1 - self.playback.next() # At track 2 - self.playback.previous() # At track 1 - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_previous_return_value(self): - self.playback.play() - self.playback.next() - self.assertEqual(self.playback.previous(), None) - - @populate_tracklist - def test_previous_does_not_trigger_playback(self): - self.playback.play() - self.playback.next() - self.playback.stop() - self.playback.previous() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_previous_at_start_of_playlist(self): - self.playback.previous() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.assertEqual(self.playback.current_track, None) - - def test_previous_for_empty_playlist(self): - self.playback.previous() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.assertEqual(self.playback.current_track, None) - - @populate_tracklist - def test_previous_skips_to_previous_track_on_failure(self): - # If backend's play() returns False, it is a failure. - self.backend.playback.play = lambda track: track != self.tracks[1] - self.playback.play(self.tracklist.tl_tracks[2]) - self.assertEqual(self.playback.current_track, self.tracks[2]) - self.playback.previous() - self.assertNotEqual(self.playback.current_track, self.tracks[1]) - self.assertEqual(self.playback.current_track, self.tracks[0]) - - @populate_tracklist - def test_next(self): - self.playback.play() - - old_position = self.playback.tracklist_position - old_uri = self.playback.current_track.uri - - self.playback.next() - - self.assertEqual( - self.playback.tracklist_position, old_position + 1) - self.assertNotEqual(self.playback.current_track.uri, old_uri) - - @populate_tracklist - def test_next_return_value(self): - self.playback.play() - self.assertEqual(self.playback.next(), None) - - @populate_tracklist - def test_next_does_not_trigger_playback(self): - self.playback.next() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_next_at_end_of_playlist(self): - self.playback.play() - - for i, track in enumerate(self.tracks): - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(self.playback.current_track, track) - self.assertEqual(self.playback.tracklist_position, i) - - self.playback.next() - - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_next_until_end_of_playlist_and_play_from_start(self): - self.playback.play() - - for _ in self.tracks: - self.playback.next() - - self.assertEqual(self.playback.current_track, None) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(self.playback.current_track, self.tracks[0]) - - def test_next_for_empty_playlist(self): - self.playback.next() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_next_skips_to_next_track_on_failure(self): - # If backend's play() returns False, it is a failure. - self.backend.playback.play = lambda track: track != self.tracks[1] - self.playback.play() - self.assertEqual(self.playback.current_track, self.tracks[0]) - self.playback.next() - self.assertNotEqual(self.playback.current_track, self.tracks[1]) - self.assertEqual(self.playback.current_track, self.tracks[2]) - - @populate_tracklist - def test_next_track_before_play(self): - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) - - @populate_tracklist - def test_next_track_during_play(self): - self.playback.play() - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) - - @populate_tracklist - def test_next_track_after_previous(self): - self.playback.play() - self.playback.next() - self.playback.previous() - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) - - def test_next_track_empty_playlist(self): - self.assertEqual(self.playback.tl_track_at_next, None) - - @populate_tracklist - def test_next_track_at_end_of_playlist(self): - self.playback.play() - for _ in self.tracklist.tl_tracks[1:]: - self.playback.next() - self.assertEqual(self.playback.tl_track_at_next, None) - - @populate_tracklist - def test_next_track_at_end_of_playlist_with_repeat(self): - self.playback.repeat = True - self.playback.play() - for _ in self.tracks[1:]: - self.playback.next() - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) - - @populate_tracklist - def test_next_track_with_random(self): - random.seed(1) - self.playback.random = True - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) - - @populate_tracklist - def test_next_with_consume(self): - self.playback.consume = True - self.playback.play() - self.playback.next() - self.assertIn(self.tracks[0], self.tracklist.tracks) - - @populate_tracklist - def test_next_with_single_and_repeat(self): - self.playback.single = True - self.playback.repeat = True - self.playback.play() - self.playback.next() - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_next_with_random(self): - # FIXME feels very fragile - random.seed(1) - self.playback.random = True - self.playback.play() - self.playback.next() - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_next_track_with_random_after_append_playlist(self): - random.seed(1) - self.playback.random = True - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) - self.tracklist.add(self.tracks[:1]) - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) - - @populate_tracklist - def test_end_of_track(self): - self.playback.play() - - old_position = self.playback.tracklist_position - old_uri = self.playback.current_track.uri - - self.playback.on_end_of_track() - - self.assertEqual( - self.playback.tracklist_position, old_position + 1) - self.assertNotEqual(self.playback.current_track.uri, old_uri) - - @populate_tracklist - def test_end_of_track_return_value(self): - self.playback.play() - self.assertEqual(self.playback.on_end_of_track(), None) - - @populate_tracklist - def test_end_of_track_does_not_trigger_playback(self): - self.playback.on_end_of_track() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_end_of_track_at_end_of_playlist(self): - self.playback.play() - - for i, track in enumerate(self.tracks): - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(self.playback.current_track, track) - self.assertEqual(self.playback.tracklist_position, i) - - self.playback.on_end_of_track() - - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_end_of_track_until_end_of_playlist_and_play_from_start(self): - self.playback.play() - - for _ in self.tracks: - self.playback.on_end_of_track() - - self.assertEqual(self.playback.current_track, None) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(self.playback.current_track, self.tracks[0]) - - def test_end_of_track_for_empty_playlist(self): - self.playback.on_end_of_track() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_end_of_track_skips_to_next_track_on_failure(self): - # If backend's play() returns False, it is a failure. - self.backend.playback.play = lambda track: track != self.tracks[1] - self.playback.play() - self.assertEqual(self.playback.current_track, self.tracks[0]) - self.playback.on_end_of_track() - self.assertNotEqual(self.playback.current_track, self.tracks[1]) - self.assertEqual(self.playback.current_track, self.tracks[2]) - - @populate_tracklist - def test_end_of_track_track_before_play(self): - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) - - @populate_tracklist - def test_end_of_track_track_during_play(self): - self.playback.play() - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) - - @populate_tracklist - def test_end_of_track_track_after_previous(self): - self.playback.play() - self.playback.on_end_of_track() - self.playback.previous() - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) - - def test_end_of_track_track_empty_playlist(self): - self.assertEqual(self.playback.tl_track_at_next, None) - - @populate_tracklist - def test_end_of_track_track_at_end_of_playlist(self): - self.playback.play() - for _ in self.tracklist.tl_tracks[1:]: - self.playback.on_end_of_track() - self.assertEqual(self.playback.tl_track_at_next, None) - - @populate_tracklist - def test_end_of_track_track_at_end_of_playlist_with_repeat(self): - self.playback.repeat = True - self.playback.play() - for _ in self.tracks[1:]: - self.playback.on_end_of_track() - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) - - @populate_tracklist - def test_end_of_track_track_with_random(self): - random.seed(1) - self.playback.random = True - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) - - @populate_tracklist - def test_end_of_track_with_consume(self): - self.playback.consume = True - self.playback.play() - self.playback.on_end_of_track() - self.assertNotIn(self.tracks[0], self.tracklist.tracks) - - @populate_tracklist - def test_end_of_track_with_random(self): - # FIXME feels very fragile - random.seed(1) - self.playback.random = True - self.playback.play() - self.playback.on_end_of_track() - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_end_of_track_track_with_random_after_append_playlist(self): - random.seed(1) - self.playback.random = True - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) - self.tracklist.add(self.tracks[:1]) - self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) - - @populate_tracklist - def test_previous_track_before_play(self): - self.assertEqual(self.playback.tl_track_at_previous, None) - - @populate_tracklist - def test_previous_track_after_play(self): - self.playback.play() - self.assertEqual(self.playback.tl_track_at_previous, None) - - @populate_tracklist - def test_previous_track_after_next(self): - self.playback.play() - self.playback.next() - self.assertEqual(self.playback.tl_track_at_previous, self.tl_tracks[0]) - - @populate_tracklist - def test_previous_track_after_previous(self): - self.playback.play() # At track 0 - self.playback.next() # At track 1 - self.playback.next() # At track 2 - self.playback.previous() # At track 1 - self.assertEqual(self.playback.tl_track_at_previous, self.tl_tracks[0]) - - def test_previous_track_empty_playlist(self): - self.assertEqual(self.playback.tl_track_at_previous, None) - - @populate_tracklist - def test_previous_track_with_consume(self): - self.playback.consume = True - for _ in self.tracks: - self.playback.next() - self.assertEqual( - self.playback.tl_track_at_previous, - self.playback.current_tl_track) - - @populate_tracklist - def test_previous_track_with_random(self): - self.playback.random = True - for _ in self.tracks: - self.playback.next() - self.assertEqual( - self.playback.tl_track_at_previous, - self.playback.current_tl_track) - - @populate_tracklist - def test_initial_current_track(self): - self.assertEqual(self.playback.current_track, None) - - @populate_tracklist - def test_current_track_during_play(self): - self.playback.play() - self.assertEqual(self.playback.current_track, self.tracks[0]) - - @populate_tracklist - def test_current_track_after_next(self): - self.playback.play() - self.playback.next() - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_initial_tracklist_position(self): - self.assertEqual(self.playback.tracklist_position, None) - - @populate_tracklist - def test_tracklist_position_during_play(self): - self.playback.play() - self.assertEqual(self.playback.tracklist_position, 0) - - @populate_tracklist - def test_tracklist_position_after_next(self): - self.playback.play() - self.playback.next() - self.assertEqual(self.playback.tracklist_position, 1) - - @populate_tracklist - def test_tracklist_position_at_end_of_playlist(self): - self.playback.play(self.tracklist.tl_tracks[-1]) - self.playback.on_end_of_track() - self.assertEqual(self.playback.tracklist_position, None) - - def test_on_tracklist_change_gets_called(self): - callback = self.playback.on_tracklist_change - - def wrapper(): - wrapper.called = True - return callback() - wrapper.called = False - - self.playback.on_tracklist_change = wrapper - self.tracklist.add([Track()]) - - self.assert_(wrapper.called) - - @unittest.SkipTest # Blocks for 10ms - @populate_tracklist - def test_end_of_track_callback_gets_called(self): - self.playback.play() - result = self.playback.seek(self.tracks[0].length - 10) - self.assertTrue(result, 'Seek failed') - message = self.core_queue.get(True, 1) - self.assertEqual('end_of_track', message['command']) - - @populate_tracklist - def test_on_tracklist_change_when_playing(self): - self.playback.play() - current_track = self.playback.current_track - self.tracklist.add([self.tracks[2]]) - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(self.playback.current_track, current_track) - - @populate_tracklist - def test_on_tracklist_change_when_stopped(self): - self.tracklist.add([self.tracks[2]]) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.assertEqual(self.playback.current_track, None) - - @populate_tracklist - def test_on_tracklist_change_when_paused(self): - self.playback.play() - self.playback.pause() - current_track = self.playback.current_track - self.tracklist.add([self.tracks[2]]) - self.assertEqual(self.playback.state, PlaybackState.PAUSED) - self.assertEqual(self.playback.current_track, current_track) - - @populate_tracklist - def test_pause_when_stopped(self): - self.playback.pause() - self.assertEqual(self.playback.state, PlaybackState.PAUSED) - - @populate_tracklist - def test_pause_when_playing(self): - self.playback.play() - self.playback.pause() - self.assertEqual(self.playback.state, PlaybackState.PAUSED) - - @populate_tracklist - def test_pause_when_paused(self): - self.playback.play() - self.playback.pause() - self.playback.pause() - self.assertEqual(self.playback.state, PlaybackState.PAUSED) - - @populate_tracklist - def test_pause_return_value(self): - self.playback.play() - self.assertEqual(self.playback.pause(), None) - - @populate_tracklist - def test_resume_when_stopped(self): - self.playback.resume() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_resume_when_playing(self): - self.playback.play() - self.playback.resume() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @populate_tracklist - def test_resume_when_paused(self): - self.playback.play() - self.playback.pause() - self.playback.resume() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @populate_tracklist - def test_resume_return_value(self): - self.playback.play() - self.playback.pause() - self.assertEqual(self.playback.resume(), None) - - @unittest.SkipTest # Uses sleep and might not work with LocalBackend - @populate_tracklist - def test_resume_continues_from_right_position(self): - self.playback.play() - time.sleep(0.2) - self.playback.pause() - self.playback.resume() - self.assertNotEqual(self.playback.time_position, 0) - - @populate_tracklist - def test_seek_when_stopped(self): - result = self.playback.seek(1000) - self.assert_(result, 'Seek return value was %s' % result) - - @populate_tracklist - def test_seek_when_stopped_updates_position(self): - self.playback.seek(1000) - position = self.playback.time_position - self.assertGreaterEqual(position, 990) - - def test_seek_on_empty_playlist(self): - self.assertFalse(self.playback.seek(0)) - - def test_seek_on_empty_playlist_updates_position(self): - self.playback.seek(0) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_seek_when_stopped_triggers_play(self): - self.playback.seek(0) - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @populate_tracklist - def test_seek_when_playing(self): - self.playback.play() - result = self.playback.seek(self.tracks[0].length - 1000) - self.assert_(result, 'Seek return value was %s' % result) - - @populate_tracklist - def test_seek_when_playing_updates_position(self): - length = self.tracklist.tracks[0].length - self.playback.play() - self.playback.seek(length - 1000) - position = self.playback.time_position - self.assertGreaterEqual(position, length - 1010) - - @populate_tracklist - def test_seek_when_paused(self): - self.playback.play() - self.playback.pause() - result = self.playback.seek(self.tracks[0].length - 1000) - self.assert_(result, 'Seek return value was %s' % result) - - @populate_tracklist - def test_seek_when_paused_updates_position(self): - length = self.tracklist.tracks[0].length - self.playback.play() - self.playback.pause() - self.playback.seek(length - 1000) - position = self.playback.time_position - self.assertGreaterEqual(position, length - 1010) - - @populate_tracklist - def test_seek_when_paused_triggers_play(self): - self.playback.play() - self.playback.pause() - self.playback.seek(0) - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @unittest.SkipTest - @populate_tracklist - def test_seek_beyond_end_of_song(self): - # FIXME need to decide return value - self.playback.play() - result = self.playback.seek(self.tracks[0].length * 100) - self.assert_(not result, 'Seek return value was %s' % result) - - @populate_tracklist - def test_seek_beyond_end_of_song_jumps_to_next_song(self): - self.playback.play() - self.playback.seek(self.tracks[0].length * 100) - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_seek_beyond_end_of_song_for_last_track(self): - self.playback.play(self.tracklist.tl_tracks[-1]) - self.playback.seek(self.tracklist.tracks[-1].length * 100) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @unittest.SkipTest - @populate_tracklist - def test_seek_beyond_start_of_song(self): - # FIXME need to decide return value - self.playback.play() - result = self.playback.seek(-1000) - self.assert_(not result, 'Seek return value was %s' % result) - - @populate_tracklist - def test_seek_beyond_start_of_song_update_postion(self): - self.playback.play() - self.playback.seek(-1000) - position = self.playback.time_position - self.assertGreaterEqual(position, 0) - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @populate_tracklist - def test_stop_when_stopped(self): - self.playback.stop() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_stop_when_playing(self): - self.playback.play() - self.playback.stop() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - @populate_tracklist - def test_stop_when_paused(self): - self.playback.play() - self.playback.pause() - self.playback.stop() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - def test_stop_return_value(self): - self.playback.play() - self.assertEqual(self.playback.stop(), None) - - def test_time_position_when_stopped(self): - future = mock.Mock() - future.get = mock.Mock(return_value=0) - self.audio.get_position = mock.Mock(return_value=future) - - self.assertEqual(self.playback.time_position, 0) - - @populate_tracklist - def test_time_position_when_stopped_with_playlist(self): - future = mock.Mock() - future.get = mock.Mock(return_value=0) - self.audio.get_position = mock.Mock(return_value=future) - - self.assertEqual(self.playback.time_position, 0) - - @unittest.SkipTest # Uses sleep and does might not work with LocalBackend - @populate_tracklist - def test_time_position_when_playing(self): - self.playback.play() - first = self.playback.time_position - time.sleep(1) - second = self.playback.time_position - self.assertGreater(second, first) - - @unittest.SkipTest # Uses sleep - @populate_tracklist - def test_time_position_when_paused(self): - self.playback.play() - time.sleep(0.2) - self.playback.pause() - time.sleep(0.2) - first = self.playback.time_position - second = self.playback.time_position - self.assertEqual(first, second) - - @populate_tracklist - def test_play_with_consume(self): - self.playback.consume = True - self.playback.play() - self.assertEqual(self.playback.current_track, self.tracks[0]) - - @populate_tracklist - def test_playlist_is_empty_after_all_tracks_are_played_with_consume(self): - self.playback.consume = True - self.playback.play() - for _ in range(len(self.tracklist.tracks)): - self.playback.on_end_of_track() - self.assertEqual(len(self.tracklist.tracks), 0) - - @populate_tracklist - def test_play_with_random(self): - random.seed(1) - self.playback.random = True - self.playback.play() - self.assertEqual(self.playback.current_track, self.tracks[2]) - - @populate_tracklist - def test_previous_with_random(self): - random.seed(1) - self.playback.random = True - self.playback.play() - self.playback.next() - current_track = self.playback.current_track - self.playback.previous() - self.assertEqual(self.playback.current_track, current_track) - - @populate_tracklist - def test_end_of_song_starts_next_track(self): - self.playback.play() - self.playback.on_end_of_track() - self.assertEqual(self.playback.current_track, self.tracks[1]) - - @populate_tracklist - def test_end_of_song_with_single_and_repeat_starts_same(self): - self.playback.single = True - self.playback.repeat = True - self.playback.play() - self.playback.on_end_of_track() - self.assertEqual(self.playback.current_track, self.tracks[0]) - - @populate_tracklist - def test_end_of_playlist_stops(self): - self.playback.play(self.tracklist.tl_tracks[-1]) - self.playback.on_end_of_track() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - def test_repeat_off_by_default(self): - self.assertEqual(self.playback.repeat, False) - - def test_random_off_by_default(self): - self.assertEqual(self.playback.random, False) - - def test_consume_off_by_default(self): - self.assertEqual(self.playback.consume, False) - - @populate_tracklist - def test_random_until_end_of_playlist(self): - self.playback.random = True - self.playback.play() - for _ in self.tracks[1:]: - self.playback.next() - self.assertEqual(self.playback.tl_track_at_next, None) - - @populate_tracklist - def test_random_until_end_of_playlist_and_play_from_start(self): - self.playback.repeat = True - for _ in self.tracks: - self.playback.next() - self.assertNotEqual(self.playback.tl_track_at_next, None) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - - @populate_tracklist - def test_random_until_end_of_playlist_with_repeat(self): - self.playback.repeat = True - self.playback.random = True - self.playback.play() - for _ in self.tracks: - self.playback.next() - self.assertNotEqual(self.playback.tl_track_at_next, None) - - @populate_tracklist - def test_played_track_during_random_not_played_again(self): - self.playback.random = True - self.playback.play() - played = [] - for _ in self.tracks: - self.assertNotIn(self.playback.current_track, played) - played.append(self.playback.current_track) - self.playback.next() - - @populate_tracklist - def test_playing_track_that_isnt_in_playlist(self): - test = lambda: self.playback.play((17, Track())) - self.assertRaises(AssertionError, test) diff --git a/tests/backends/base/playlists.py b/tests/backends/base/playlists.py deleted file mode 100644 index 139c21c6d2..0000000000 --- a/tests/backends/base/playlists.py +++ /dev/null @@ -1,102 +0,0 @@ -from __future__ import unicode_literals - -import unittest - -import pykka - -from mopidy import audio, core -from mopidy.models import Playlist - - -class PlaylistsControllerTest(object): - config = {} - - def setUp(self): - self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start( - config=self.config, audio=self.audio).proxy() - self.core = core.Core(backends=[self.backend]) - - def tearDown(self): - pykka.ActorRegistry.stop_all() - - def test_create_returns_playlist_with_name_set(self): - playlist = self.core.playlists.create('test') - self.assertEqual(playlist.name, 'test') - - def test_create_returns_playlist_with_uri_set(self): - playlist = self.core.playlists.create('test') - self.assert_(playlist.uri) - - def test_create_adds_playlist_to_playlists_collection(self): - playlist = self.core.playlists.create('test') - self.assert_(self.core.playlists.playlists) - self.assertIn(playlist, self.core.playlists.playlists) - - def test_playlists_empty_to_start_with(self): - self.assert_(not self.core.playlists.playlists) - - def test_delete_non_existant_playlist(self): - self.core.playlists.delete('file:///unknown/playlist') - - def test_delete_playlist_removes_it_from_the_collection(self): - playlist = self.core.playlists.create('test') - self.assertIn(playlist, self.core.playlists.playlists) - - self.core.playlists.delete(playlist.uri) - - self.assertNotIn(playlist, self.core.playlists.playlists) - - def test_filter_without_criteria(self): - self.assertEqual( - self.core.playlists.playlists, self.core.playlists.filter()) - - def test_filter_with_wrong_criteria(self): - self.assertEqual([], self.core.playlists.filter(name='foo')) - - def test_filter_with_right_criteria(self): - playlist = self.core.playlists.create('test') - playlists = self.core.playlists.filter(name='test') - self.assertEqual([playlist], playlists) - - def test_filter_by_name_returns_single_match(self): - playlist = Playlist(name='b') - self.backend.playlists.playlists = [Playlist(name='a'), playlist] - self.assertEqual([playlist], self.core.playlists.filter(name='b')) - - def test_filter_by_name_returns_multiple_matches(self): - playlist = Playlist(name='b') - self.backend.playlists.playlists = [ - playlist, Playlist(name='a'), Playlist(name='b')] - playlists = self.core.playlists.filter(name='b') - self.assertIn(playlist, playlists) - self.assertEqual(2, len(playlists)) - - def test_filter_by_name_returns_no_matches(self): - self.backend.playlists.playlists = [ - Playlist(name='a'), Playlist(name='b')] - self.assertEqual([], self.core.playlists.filter(name='c')) - - def test_lookup_finds_playlist_by_uri(self): - original_playlist = self.core.playlists.create('test') - - looked_up_playlist = self.core.playlists.lookup(original_playlist.uri) - - self.assertEqual(original_playlist, looked_up_playlist) - - @unittest.SkipTest - def test_refresh(self): - pass - - def test_save_replaces_existing_playlist_with_updated_playlist(self): - playlist1 = self.core.playlists.create('test1') - self.assertIn(playlist1, self.core.playlists.playlists) - - playlist2 = playlist1.copy(name='test2') - playlist2 = self.core.playlists.save(playlist2) - self.assertNotIn(playlist1, self.core.playlists.playlists) - self.assertIn(playlist2, self.core.playlists.playlists) - - @unittest.SkipTest - def test_playlist_with_unknown_track(self): - pass diff --git a/tests/backends/base/tracklist.py b/tests/backends/base/tracklist.py deleted file mode 100644 index 5140d3aa26..0000000000 --- a/tests/backends/base/tracklist.py +++ /dev/null @@ -1,295 +0,0 @@ -from __future__ import unicode_literals - -import random - -import pykka - -from mopidy import audio, core -from mopidy.core import PlaybackState -from mopidy.models import TlTrack, Playlist, Track - -from tests.backends.base import populate_tracklist - - -class TracklistControllerTest(object): - tracks = [] - config = {} - - def setUp(self): - self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start( - config=self.config, audio=self.audio).proxy() - self.core = core.Core(audio=self.audio, backends=[self.backend]) - self.controller = self.core.tracklist - self.playback = self.core.playback - - assert len(self.tracks) == 3, 'Need three tracks to run tests.' - - def tearDown(self): - pykka.ActorRegistry.stop_all() - - def test_length(self): - self.assertEqual(0, len(self.controller.tl_tracks)) - self.assertEqual(0, self.controller.length) - self.controller.add(self.tracks) - self.assertEqual(3, len(self.controller.tl_tracks)) - self.assertEqual(3, self.controller.length) - - def test_add(self): - for track in self.tracks: - tl_tracks = self.controller.add([track]) - self.assertEqual(track, self.controller.tracks[-1]) - self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1]) - self.assertEqual(track, tl_tracks[0].track) - - def test_add_at_position(self): - for track in self.tracks[:-1]: - tl_tracks = self.controller.add([track], 0) - self.assertEqual(track, self.controller.tracks[0]) - self.assertEqual(tl_tracks[0], self.controller.tl_tracks[0]) - self.assertEqual(track, tl_tracks[0].track) - - @populate_tracklist - def test_add_at_position_outside_of_playlist(self): - for track in self.tracks: - tl_tracks = self.controller.add([track], len(self.tracks) + 2) - self.assertEqual(track, self.controller.tracks[-1]) - self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1]) - self.assertEqual(track, tl_tracks[0].track) - - @populate_tracklist - def test_filter_by_tlid(self): - tl_track = self.controller.tl_tracks[1] - self.assertEqual( - [tl_track], self.controller.filter(tlid=tl_track.tlid)) - - @populate_tracklist - def test_filter_by_uri(self): - tl_track = self.controller.tl_tracks[1] - self.assertEqual( - [tl_track], self.controller.filter(uri=tl_track.track.uri)) - - @populate_tracklist - def test_filter_by_uri_returns_nothing_for_invalid_uri(self): - self.assertEqual([], self.controller.filter(uri='foobar')) - - def test_filter_by_uri_returns_single_match(self): - track = Track(uri='a') - self.controller.add([Track(uri='z'), track, Track(uri='y')]) - self.assertEqual(track, self.controller.filter(uri='a')[0].track) - - def test_filter_by_uri_returns_multiple_matches(self): - track = Track(uri='a') - self.controller.add([Track(uri='z'), track, track]) - tl_tracks = self.controller.filter(uri='a') - self.assertEqual(track, tl_tracks[0].track) - self.assertEqual(track, tl_tracks[1].track) - - def test_filter_by_uri_returns_nothing_if_no_match(self): - self.controller.playlist = Playlist( - tracks=[Track(uri='z'), Track(uri='y')]) - self.assertEqual([], self.controller.filter(uri='a')) - - def test_filter_by_multiple_criteria_returns_elements_matching_all(self): - track1 = Track(uri='a', name='x') - track2 = Track(uri='b', name='x') - track3 = Track(uri='b', name='y') - self.controller.add([track1, track2, track3]) - self.assertEqual( - track1, self.controller.filter(uri='a', name='x')[0].track) - self.assertEqual( - track2, self.controller.filter(uri='b', name='x')[0].track) - self.assertEqual( - track3, self.controller.filter(uri='b', name='y')[0].track) - - def test_filter_by_criteria_that_is_not_present_in_all_elements(self): - track1 = Track() - track2 = Track(uri='b') - track3 = Track() - self.controller.add([track1, track2, track3]) - self.assertEqual(track2, self.controller.filter(uri='b')[0].track) - - @populate_tracklist - def test_clear(self): - self.controller.clear() - self.assertEqual(len(self.controller.tracks), 0) - - def test_clear_empty_playlist(self): - self.controller.clear() - self.assertEqual(len(self.controller.tracks), 0) - - @populate_tracklist - def test_clear_when_playing(self): - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.controller.clear() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - - def test_add_appends_to_the_tracklist(self): - self.controller.add([Track(uri='a'), Track(uri='b')]) - self.assertEqual(len(self.controller.tracks), 2) - self.controller.add([Track(uri='c'), Track(uri='d')]) - self.assertEqual(len(self.controller.tracks), 4) - self.assertEqual(self.controller.tracks[0].uri, 'a') - self.assertEqual(self.controller.tracks[1].uri, 'b') - self.assertEqual(self.controller.tracks[2].uri, 'c') - self.assertEqual(self.controller.tracks[3].uri, 'd') - - def test_add_does_not_reset_version(self): - version = self.controller.version - self.controller.add([]) - self.assertEqual(self.controller.version, version) - - @populate_tracklist - def test_add_preserves_playing_state(self): - self.playback.play() - track = self.playback.current_track - self.controller.add(self.controller.tracks[1:2]) - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(self.playback.current_track, track) - - @populate_tracklist - def test_add_preserves_stopped_state(self): - self.controller.add(self.controller.tracks[1:2]) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.assertEqual(self.playback.current_track, None) - - @populate_tracklist - def test_add_returns_the_tl_tracks_that_was_added(self): - tl_tracks = self.controller.add(self.controller.tracks[1:2]) - self.assertEqual(tl_tracks[0].track, self.controller.tracks[1]) - - def test_index_returns_index_of_track(self): - tl_tracks = self.controller.add(self.tracks) - self.assertEquals(0, self.controller.index(tl_tracks[0])) - self.assertEquals(1, self.controller.index(tl_tracks[1])) - self.assertEquals(2, self.controller.index(tl_tracks[2])) - - def test_index_raises_value_error_if_item_not_found(self): - test = lambda: self.controller.index(TlTrack(0, Track())) - self.assertRaises(ValueError, test) - - @populate_tracklist - def test_move_single(self): - self.controller.move(0, 0, 2) - - tracks = self.controller.tracks - self.assertEqual(tracks[2], self.tracks[0]) - - @populate_tracklist - def test_move_group(self): - self.controller.move(0, 2, 1) - - tracks = self.controller.tracks - self.assertEqual(tracks[1], self.tracks[0]) - self.assertEqual(tracks[2], self.tracks[1]) - - @populate_tracklist - def test_moving_track_outside_of_playlist(self): - tracks = len(self.controller.tracks) - test = lambda: self.controller.move(0, 0, tracks + 5) - self.assertRaises(AssertionError, test) - - @populate_tracklist - def test_move_group_outside_of_playlist(self): - tracks = len(self.controller.tracks) - test = lambda: self.controller.move(0, 2, tracks + 5) - self.assertRaises(AssertionError, test) - - @populate_tracklist - def test_move_group_out_of_range(self): - tracks = len(self.controller.tracks) - test = lambda: self.controller.move(tracks + 2, tracks + 3, 0) - self.assertRaises(AssertionError, test) - - @populate_tracklist - def test_move_group_invalid_group(self): - test = lambda: self.controller.move(2, 1, 0) - self.assertRaises(AssertionError, test) - - def test_tracks_attribute_is_immutable(self): - tracks1 = self.controller.tracks - tracks2 = self.controller.tracks - self.assertNotEqual(id(tracks1), id(tracks2)) - - @populate_tracklist - def test_remove(self): - track1 = self.controller.tracks[1] - track2 = self.controller.tracks[2] - version = self.controller.version - self.controller.remove(uri=track1.uri) - self.assertLess(version, self.controller.version) - self.assertNotIn(track1, self.controller.tracks) - self.assertEqual(track2, self.controller.tracks[1]) - - @populate_tracklist - def test_removing_track_that_does_not_exist_does_nothing(self): - self.controller.remove(uri='/nonexistant') - - def test_removing_from_empty_playlist_does_nothing(self): - self.controller.remove(uri='/nonexistant') - - @populate_tracklist - def test_shuffle(self): - random.seed(1) - self.controller.shuffle() - - shuffled_tracks = self.controller.tracks - - self.assertNotEqual(self.tracks, shuffled_tracks) - self.assertEqual(set(self.tracks), set(shuffled_tracks)) - - @populate_tracklist - def test_shuffle_subset(self): - random.seed(1) - self.controller.shuffle(1, 3) - - shuffled_tracks = self.controller.tracks - - self.assertNotEqual(self.tracks, shuffled_tracks) - self.assertEqual(self.tracks[0], shuffled_tracks[0]) - self.assertEqual(set(self.tracks), set(shuffled_tracks)) - - @populate_tracklist - def test_shuffle_invalid_subset(self): - test = lambda: self.controller.shuffle(3, 1) - self.assertRaises(AssertionError, test) - - @populate_tracklist - def test_shuffle_superset(self): - tracks = len(self.controller.tracks) - test = lambda: self.controller.shuffle(1, tracks + 5) - self.assertRaises(AssertionError, test) - - @populate_tracklist - def test_shuffle_open_subset(self): - random.seed(1) - self.controller.shuffle(1) - - shuffled_tracks = self.controller.tracks - - self.assertNotEqual(self.tracks, shuffled_tracks) - self.assertEqual(self.tracks[0], shuffled_tracks[0]) - self.assertEqual(set(self.tracks), set(shuffled_tracks)) - - @populate_tracklist - def test_slice_returns_a_subset_of_tracks(self): - track_slice = self.controller.slice(1, 3) - self.assertEqual(2, len(track_slice)) - self.assertEqual(self.tracks[1], track_slice[0].track) - self.assertEqual(self.tracks[2], track_slice[1].track) - - @populate_tracklist - def test_slice_returns_empty_list_if_indexes_outside_tracks_list(self): - self.assertEqual(0, len(self.controller.slice(7, 8))) - self.assertEqual(0, len(self.controller.slice(-1, 1))) - - def test_version_does_not_change_when_adding_nothing(self): - version = self.controller.version - self.controller.add([]) - self.assertEquals(version, self.controller.version) - - def test_version_increases_when_adding_something(self): - version = self.controller.version - self.controller.add([Track()]) - self.assertLess(version, self.controller.version) diff --git a/tests/backends/local/__init__.py b/tests/backends/local/__init__.py index 1738722f63..f408139f67 100644 --- a/tests/backends/local/__init__.py +++ b/tests/backends/local/__init__.py @@ -1,4 +1,15 @@ from __future__ import unicode_literals -generate_song = lambda i: 'local:track:song%s.wav' % i +def generate_song(i): + return 'local:track:song%s.wav' % i + + +def populate_tracklist(func): + def wrapper(self): + self.tl_tracks = self.core.tracklist.add(self.tracks) + return func(self) + + wrapper.__name__ = func.__name__ + wrapper.__doc__ = func.__doc__ + return wrapper diff --git a/tests/backends/local/events_test.py b/tests/backends/local/events_test.py index 7b7ceadd2f..725c580f1c 100644 --- a/tests/backends/local/events_test.py +++ b/tests/backends/local/events_test.py @@ -2,14 +2,18 @@ import unittest +import mock +import pykka + +from mopidy import core, audio +from mopidy.backends import listener from mopidy.backends.local import actor from tests import path_to_data_dir -from tests.backends.base import events -class LocalBackendEventsTest(events.BackendEventsTest, unittest.TestCase): - backend_class = actor.LocalBackend +@mock.patch.object(listener.BackendListener, 'send') +class LocalBackendEventsTest(unittest.TestCase): config = { 'local': { 'media_dir': path_to_data_dir(''), @@ -17,3 +21,17 @@ class LocalBackendEventsTest(events.BackendEventsTest, unittest.TestCase): 'tag_cache_file': path_to_data_dir('empty_tag_cache'), } } + + def setUp(self): + self.audio = audio.DummyAudio.start().proxy() + self.backend = actor.LocalBackend.start( + config=self.config, audio=self.audio).proxy() + self.core = core.Core.start(backends=[self.backend]).proxy() + + def tearDown(self): + pykka.ActorRegistry.stop_all() + + def test_playlists_refresh_sends_playlists_loaded_event(self, send): + send.reset_mock() + self.core.playlists.refresh().get() + self.assertEqual(send.call_args[0][0], 'playlists_loaded') diff --git a/tests/backends/local/library_test.py b/tests/backends/local/library_test.py index c249a10e6e..8f9885039f 100644 --- a/tests/backends/local/library_test.py +++ b/tests/backends/local/library_test.py @@ -2,14 +2,30 @@ import unittest +import pykka + +from mopidy import core from mopidy.backends.local import actor +from mopidy.models import Track, Album, Artist from tests import path_to_data_dir -from tests.backends.base.library import LibraryControllerTest -class LocalLibraryControllerTest(LibraryControllerTest, unittest.TestCase): - backend_class = actor.LocalBackend +class LocalLibraryControllerTest(unittest.TestCase): + artists = [Artist(name='artist1'), Artist(name='artist2'), Artist()] + + albums = [ + Album(name='album1', artists=artists[:1]), + Album(name='album2', artists=artists[1:2]), + Album()] + + tracks = [ + Track(uri='local:track:path1', name='track1', artists=artists[:1], + album=albums[0], date='2001-02-03', length=4000), + Track(uri='local:track:path2', name='track2', artists=artists[1:2], + album=albums[1], date='2002', length=4000), + Track()] + config = { 'local': { 'media_dir': path_to_data_dir(''), @@ -17,3 +33,182 @@ class LocalLibraryControllerTest(LibraryControllerTest, unittest.TestCase): 'tag_cache_file': path_to_data_dir('library_tag_cache'), } } + + def setUp(self): + self.backend = actor.LocalBackend.start( + config=self.config, audio=None).proxy() + self.core = core.Core(backends=[self.backend]) + self.library = self.core.library + + def tearDown(self): + pykka.ActorRegistry.stop_all() + + def test_refresh(self): + self.library.refresh() + + @unittest.SkipTest + def test_refresh_uri(self): + pass + + @unittest.SkipTest + def test_refresh_missing_uri(self): + pass + + def test_lookup(self): + tracks = self.library.lookup(self.tracks[0].uri) + self.assertEqual(tracks, self.tracks[0:1]) + + def test_lookup_unknown_track(self): + tracks = self.library.lookup('fake uri') + self.assertEqual(tracks, []) + + def test_find_exact_no_hits(self): + result = self.library.find_exact(track=['unknown track']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.find_exact(artist=['unknown artist']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.find_exact(album=['unknown artist']) + self.assertEqual(list(result[0].tracks), []) + + def test_find_exact_uri(self): + track_1_uri = 'local:track:path1' + result = self.library.find_exact(uri=track_1_uri) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + track_2_uri = 'local:track:path2' + result = self.library.find_exact(uri=track_2_uri) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_find_exact_track(self): + result = self.library.find_exact(track=['track1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.find_exact(track=['track2']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_find_exact_artist(self): + result = self.library.find_exact(artist=['artist1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.find_exact(artist=['artist2']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_find_exact_album(self): + result = self.library.find_exact(album=['album1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.find_exact(album=['album2']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_find_exact_date(self): + result = self.library.find_exact(date=['2001']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.find_exact(date=['2001-02-03']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.find_exact(date=['2002']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_find_exact_wrong_type(self): + test = lambda: self.library.find_exact(wrong=['test']) + self.assertRaises(LookupError, test) + + def test_find_exact_with_empty_query(self): + test = lambda: self.library.find_exact(artist=['']) + self.assertRaises(LookupError, test) + + test = lambda: self.library.find_exact(track=['']) + self.assertRaises(LookupError, test) + + test = lambda: self.library.find_exact(album=['']) + self.assertRaises(LookupError, test) + + def test_search_no_hits(self): + result = self.library.search(track=['unknown track']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.search(artist=['unknown artist']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.search(album=['unknown artist']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.search(uri=['unknown']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.search(any=['unknown']) + self.assertEqual(list(result[0].tracks), []) + + def test_search_uri(self): + result = self.library.search(uri=['TH1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.search(uri=['TH2']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_search_track(self): + result = self.library.search(track=['Rack1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.search(track=['Rack2']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_search_artist(self): + result = self.library.search(artist=['Tist1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.search(artist=['Tist2']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_search_album(self): + result = self.library.search(album=['Bum1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.search(album=['Bum2']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_search_date(self): + result = self.library.search(date=['2001']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.search(date=['2001-02-03']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + result = self.library.search(date=['2001-02-04']) + self.assertEqual(list(result[0].tracks), []) + + result = self.library.search(date=['2002']) + self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + + def test_search_any(self): + result = self.library.search(any=['Tist1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + result = self.library.search(any=['Rack1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + result = self.library.search(any=['Bum1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + result = self.library.search(any=['TH1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + def test_search_wrong_type(self): + test = lambda: self.library.search(wrong=['test']) + self.assertRaises(LookupError, test) + + def test_search_with_empty_query(self): + test = lambda: self.library.search(artist=['']) + self.assertRaises(LookupError, test) + + test = lambda: self.library.search(track=['']) + self.assertRaises(LookupError, test) + + test = lambda: self.library.search(album=['']) + self.assertRaises(LookupError, test) + + test = lambda: self.library.search(uri=['']) + self.assertRaises(LookupError, test) + + test = lambda: self.library.search(any=['']) + self.assertRaises(LookupError, test) diff --git a/tests/backends/local/playback_test.py b/tests/backends/local/playback_test.py index 530f09c8d8..c37eb91dfd 100644 --- a/tests/backends/local/playback_test.py +++ b/tests/backends/local/playback_test.py @@ -1,18 +1,25 @@ from __future__ import unicode_literals +import mock +import random +import time import unittest +import pykka + +from mopidy import audio, core from mopidy.backends.local import actor from mopidy.core import PlaybackState from mopidy.models import Track from tests import path_to_data_dir -from tests.backends.base.playback import PlaybackControllerTest -from tests.backends.local import generate_song +from tests.backends.local import generate_song, populate_tracklist + +# TODO Test 'playlist repeat', e.g. repeat=1,single=0 -class LocalPlaybackControllerTest(PlaybackControllerTest, unittest.TestCase): - backend_class = actor.LocalBackend + +class LocalPlaybackControllerTest(unittest.TestCase): config = { 'local': { 'media_dir': path_to_data_dir(''), @@ -27,6 +34,22 @@ def add_track(self, uri): track = Track(uri=uri, length=4464) self.tracklist.add([track]) + def setUp(self): + self.audio = audio.DummyAudio.start().proxy() + self.backend = actor.LocalBackend.start( + config=self.config, audio=self.audio).proxy() + self.core = core.Core(backends=[self.backend]) + self.playback = self.core.playback + self.tracklist = self.core.tracklist + + assert len(self.tracks) >= 3, \ + 'Need at least three tracks to run tests.' + assert self.tracks[0].length >= 2000, \ + 'First song needs to be at least 2000 miliseconds' + + def tearDown(self): + pykka.ActorRegistry.stop_all() + def test_uri_scheme(self): self.assertNotIn('file', self.core.uri_schemes) self.assertIn('local', self.core.uri_schemes) @@ -45,3 +68,842 @@ def test_play_flac(self): self.add_track('local:track:blank.flac') self.playback.play() self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + def test_initial_state_is_stopped(self): + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + def test_play_with_empty_playlist(self): + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + def test_play_with_empty_playlist_return_value(self): + self.assertEqual(self.playback.play(), None) + + @populate_tracklist + def test_play_state(self): + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @populate_tracklist + def test_play_return_value(self): + self.assertEqual(self.playback.play(), None) + + @populate_tracklist + def test_play_track_state(self): + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.playback.play(self.tracklist.tl_tracks[-1]) + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @populate_tracklist + def test_play_track_return_value(self): + self.assertEqual(self.playback.play( + self.tracklist.tl_tracks[-1]), None) + + @populate_tracklist + def test_play_when_playing(self): + self.playback.play() + track = self.playback.current_track + self.playback.play() + self.assertEqual(track, self.playback.current_track) + + @populate_tracklist + def test_play_when_paused(self): + self.playback.play() + track = self.playback.current_track + self.playback.pause() + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(track, self.playback.current_track) + + @populate_tracklist + def test_play_when_pause_after_next(self): + self.playback.play() + self.playback.next() + self.playback.next() + track = self.playback.current_track + self.playback.pause() + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(track, self.playback.current_track) + + @populate_tracklist + def test_play_sets_current_track(self): + self.playback.play() + self.assertEqual(self.playback.current_track, self.tracks[0]) + + @populate_tracklist + def test_play_track_sets_current_track(self): + self.playback.play(self.tracklist.tl_tracks[-1]) + self.assertEqual(self.playback.current_track, self.tracks[-1]) + + @populate_tracklist + def test_play_skips_to_next_track_on_failure(self): + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[0] + self.playback.play() + self.assertNotEqual(self.playback.current_track, self.tracks[0]) + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_current_track_after_completed_playlist(self): + self.playback.play(self.tracklist.tl_tracks[-1]) + self.playback.on_end_of_track() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.assertEqual(self.playback.current_track, None) + + self.playback.play(self.tracklist.tl_tracks[-1]) + self.playback.next() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.assertEqual(self.playback.current_track, None) + + @populate_tracklist + def test_previous(self): + self.playback.play() + self.playback.next() + self.playback.previous() + self.assertEqual(self.playback.current_track, self.tracks[0]) + + @populate_tracklist + def test_previous_more(self): + self.playback.play() # At track 0 + self.playback.next() # At track 1 + self.playback.next() # At track 2 + self.playback.previous() # At track 1 + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_previous_return_value(self): + self.playback.play() + self.playback.next() + self.assertEqual(self.playback.previous(), None) + + @populate_tracklist + def test_previous_does_not_trigger_playback(self): + self.playback.play() + self.playback.next() + self.playback.stop() + self.playback.previous() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_previous_at_start_of_playlist(self): + self.playback.previous() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.assertEqual(self.playback.current_track, None) + + def test_previous_for_empty_playlist(self): + self.playback.previous() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.assertEqual(self.playback.current_track, None) + + @populate_tracklist + def test_previous_skips_to_previous_track_on_failure(self): + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[1] + self.playback.play(self.tracklist.tl_tracks[2]) + self.assertEqual(self.playback.current_track, self.tracks[2]) + self.playback.previous() + self.assertNotEqual(self.playback.current_track, self.tracks[1]) + self.assertEqual(self.playback.current_track, self.tracks[0]) + + @populate_tracklist + def test_next(self): + self.playback.play() + + old_position = self.playback.tracklist_position + old_uri = self.playback.current_track.uri + + self.playback.next() + + self.assertEqual( + self.playback.tracklist_position, old_position + 1) + self.assertNotEqual(self.playback.current_track.uri, old_uri) + + @populate_tracklist + def test_next_return_value(self): + self.playback.play() + self.assertEqual(self.playback.next(), None) + + @populate_tracklist + def test_next_does_not_trigger_playback(self): + self.playback.next() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_next_at_end_of_playlist(self): + self.playback.play() + + for i, track in enumerate(self.tracks): + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(self.playback.current_track, track) + self.assertEqual(self.playback.tracklist_position, i) + + self.playback.next() + + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_next_until_end_of_playlist_and_play_from_start(self): + self.playback.play() + + for _ in self.tracks: + self.playback.next() + + self.assertEqual(self.playback.current_track, None) + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(self.playback.current_track, self.tracks[0]) + + def test_next_for_empty_playlist(self): + self.playback.next() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_next_skips_to_next_track_on_failure(self): + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[1] + self.playback.play() + self.assertEqual(self.playback.current_track, self.tracks[0]) + self.playback.next() + self.assertNotEqual(self.playback.current_track, self.tracks[1]) + self.assertEqual(self.playback.current_track, self.tracks[2]) + + @populate_tracklist + def test_next_track_before_play(self): + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) + + @populate_tracklist + def test_next_track_during_play(self): + self.playback.play() + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) + + @populate_tracklist + def test_next_track_after_previous(self): + self.playback.play() + self.playback.next() + self.playback.previous() + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) + + def test_next_track_empty_playlist(self): + self.assertEqual(self.playback.tl_track_at_next, None) + + @populate_tracklist + def test_next_track_at_end_of_playlist(self): + self.playback.play() + for _ in self.tracklist.tl_tracks[1:]: + self.playback.next() + self.assertEqual(self.playback.tl_track_at_next, None) + + @populate_tracklist + def test_next_track_at_end_of_playlist_with_repeat(self): + self.playback.repeat = True + self.playback.play() + for _ in self.tracks[1:]: + self.playback.next() + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) + + @populate_tracklist + def test_next_track_with_random(self): + random.seed(1) + self.playback.random = True + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) + + @populate_tracklist + def test_next_with_consume(self): + self.playback.consume = True + self.playback.play() + self.playback.next() + self.assertIn(self.tracks[0], self.tracklist.tracks) + + @populate_tracklist + def test_next_with_single_and_repeat(self): + self.playback.single = True + self.playback.repeat = True + self.playback.play() + self.playback.next() + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_next_with_random(self): + # FIXME feels very fragile + random.seed(1) + self.playback.random = True + self.playback.play() + self.playback.next() + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_next_track_with_random_after_append_playlist(self): + random.seed(1) + self.playback.random = True + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) + self.tracklist.add(self.tracks[:1]) + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) + + @populate_tracklist + def test_end_of_track(self): + self.playback.play() + + old_position = self.playback.tracklist_position + old_uri = self.playback.current_track.uri + + self.playback.on_end_of_track() + + self.assertEqual( + self.playback.tracklist_position, old_position + 1) + self.assertNotEqual(self.playback.current_track.uri, old_uri) + + @populate_tracklist + def test_end_of_track_return_value(self): + self.playback.play() + self.assertEqual(self.playback.on_end_of_track(), None) + + @populate_tracklist + def test_end_of_track_does_not_trigger_playback(self): + self.playback.on_end_of_track() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_end_of_track_at_end_of_playlist(self): + self.playback.play() + + for i, track in enumerate(self.tracks): + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(self.playback.current_track, track) + self.assertEqual(self.playback.tracklist_position, i) + + self.playback.on_end_of_track() + + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_end_of_track_until_end_of_playlist_and_play_from_start(self): + self.playback.play() + + for _ in self.tracks: + self.playback.on_end_of_track() + + self.assertEqual(self.playback.current_track, None) + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(self.playback.current_track, self.tracks[0]) + + def test_end_of_track_for_empty_playlist(self): + self.playback.on_end_of_track() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_end_of_track_skips_to_next_track_on_failure(self): + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[1] + self.playback.play() + self.assertEqual(self.playback.current_track, self.tracks[0]) + self.playback.on_end_of_track() + self.assertNotEqual(self.playback.current_track, self.tracks[1]) + self.assertEqual(self.playback.current_track, self.tracks[2]) + + @populate_tracklist + def test_end_of_track_track_before_play(self): + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) + + @populate_tracklist + def test_end_of_track_track_during_play(self): + self.playback.play() + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) + + @populate_tracklist + def test_end_of_track_track_after_previous(self): + self.playback.play() + self.playback.on_end_of_track() + self.playback.previous() + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) + + def test_end_of_track_track_empty_playlist(self): + self.assertEqual(self.playback.tl_track_at_next, None) + + @populate_tracklist + def test_end_of_track_track_at_end_of_playlist(self): + self.playback.play() + for _ in self.tracklist.tl_tracks[1:]: + self.playback.on_end_of_track() + self.assertEqual(self.playback.tl_track_at_next, None) + + @populate_tracklist + def test_end_of_track_track_at_end_of_playlist_with_repeat(self): + self.playback.repeat = True + self.playback.play() + for _ in self.tracks[1:]: + self.playback.on_end_of_track() + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0]) + + @populate_tracklist + def test_end_of_track_track_with_random(self): + random.seed(1) + self.playback.random = True + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) + + @populate_tracklist + def test_end_of_track_with_consume(self): + self.playback.consume = True + self.playback.play() + self.playback.on_end_of_track() + self.assertNotIn(self.tracks[0], self.tracklist.tracks) + + @populate_tracklist + def test_end_of_track_with_random(self): + # FIXME feels very fragile + random.seed(1) + self.playback.random = True + self.playback.play() + self.playback.on_end_of_track() + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_end_of_track_track_with_random_after_append_playlist(self): + random.seed(1) + self.playback.random = True + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2]) + self.tracklist.add(self.tracks[:1]) + self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1]) + + @populate_tracklist + def test_previous_track_before_play(self): + self.assertEqual(self.playback.tl_track_at_previous, None) + + @populate_tracklist + def test_previous_track_after_play(self): + self.playback.play() + self.assertEqual(self.playback.tl_track_at_previous, None) + + @populate_tracklist + def test_previous_track_after_next(self): + self.playback.play() + self.playback.next() + self.assertEqual(self.playback.tl_track_at_previous, self.tl_tracks[0]) + + @populate_tracklist + def test_previous_track_after_previous(self): + self.playback.play() # At track 0 + self.playback.next() # At track 1 + self.playback.next() # At track 2 + self.playback.previous() # At track 1 + self.assertEqual(self.playback.tl_track_at_previous, self.tl_tracks[0]) + + def test_previous_track_empty_playlist(self): + self.assertEqual(self.playback.tl_track_at_previous, None) + + @populate_tracklist + def test_previous_track_with_consume(self): + self.playback.consume = True + for _ in self.tracks: + self.playback.next() + self.assertEqual( + self.playback.tl_track_at_previous, + self.playback.current_tl_track) + + @populate_tracklist + def test_previous_track_with_random(self): + self.playback.random = True + for _ in self.tracks: + self.playback.next() + self.assertEqual( + self.playback.tl_track_at_previous, + self.playback.current_tl_track) + + @populate_tracklist + def test_initial_current_track(self): + self.assertEqual(self.playback.current_track, None) + + @populate_tracklist + def test_current_track_during_play(self): + self.playback.play() + self.assertEqual(self.playback.current_track, self.tracks[0]) + + @populate_tracklist + def test_current_track_after_next(self): + self.playback.play() + self.playback.next() + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_initial_tracklist_position(self): + self.assertEqual(self.playback.tracklist_position, None) + + @populate_tracklist + def test_tracklist_position_during_play(self): + self.playback.play() + self.assertEqual(self.playback.tracklist_position, 0) + + @populate_tracklist + def test_tracklist_position_after_next(self): + self.playback.play() + self.playback.next() + self.assertEqual(self.playback.tracklist_position, 1) + + @populate_tracklist + def test_tracklist_position_at_end_of_playlist(self): + self.playback.play(self.tracklist.tl_tracks[-1]) + self.playback.on_end_of_track() + self.assertEqual(self.playback.tracklist_position, None) + + def test_on_tracklist_change_gets_called(self): + callback = self.playback.on_tracklist_change + + def wrapper(): + wrapper.called = True + return callback() + wrapper.called = False + + self.playback.on_tracklist_change = wrapper + self.tracklist.add([Track()]) + + self.assert_(wrapper.called) + + @unittest.SkipTest # Blocks for 10ms + @populate_tracklist + def test_end_of_track_callback_gets_called(self): + self.playback.play() + result = self.playback.seek(self.tracks[0].length - 10) + self.assertTrue(result, 'Seek failed') + message = self.core_queue.get(True, 1) + self.assertEqual('end_of_track', message['command']) + + @populate_tracklist + def test_on_tracklist_change_when_playing(self): + self.playback.play() + current_track = self.playback.current_track + self.tracklist.add([self.tracks[2]]) + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(self.playback.current_track, current_track) + + @populate_tracklist + def test_on_tracklist_change_when_stopped(self): + self.tracklist.add([self.tracks[2]]) + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.assertEqual(self.playback.current_track, None) + + @populate_tracklist + def test_on_tracklist_change_when_paused(self): + self.playback.play() + self.playback.pause() + current_track = self.playback.current_track + self.tracklist.add([self.tracks[2]]) + self.assertEqual(self.playback.state, PlaybackState.PAUSED) + self.assertEqual(self.playback.current_track, current_track) + + @populate_tracklist + def test_pause_when_stopped(self): + self.playback.pause() + self.assertEqual(self.playback.state, PlaybackState.PAUSED) + + @populate_tracklist + def test_pause_when_playing(self): + self.playback.play() + self.playback.pause() + self.assertEqual(self.playback.state, PlaybackState.PAUSED) + + @populate_tracklist + def test_pause_when_paused(self): + self.playback.play() + self.playback.pause() + self.playback.pause() + self.assertEqual(self.playback.state, PlaybackState.PAUSED) + + @populate_tracklist + def test_pause_return_value(self): + self.playback.play() + self.assertEqual(self.playback.pause(), None) + + @populate_tracklist + def test_resume_when_stopped(self): + self.playback.resume() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_resume_when_playing(self): + self.playback.play() + self.playback.resume() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @populate_tracklist + def test_resume_when_paused(self): + self.playback.play() + self.playback.pause() + self.playback.resume() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @populate_tracklist + def test_resume_return_value(self): + self.playback.play() + self.playback.pause() + self.assertEqual(self.playback.resume(), None) + + @unittest.SkipTest # Uses sleep and might not work with LocalBackend + @populate_tracklist + def test_resume_continues_from_right_position(self): + self.playback.play() + time.sleep(0.2) + self.playback.pause() + self.playback.resume() + self.assertNotEqual(self.playback.time_position, 0) + + @populate_tracklist + def test_seek_when_stopped(self): + result = self.playback.seek(1000) + self.assert_(result, 'Seek return value was %s' % result) + + @populate_tracklist + def test_seek_when_stopped_updates_position(self): + self.playback.seek(1000) + position = self.playback.time_position + self.assertGreaterEqual(position, 990) + + def test_seek_on_empty_playlist(self): + self.assertFalse(self.playback.seek(0)) + + def test_seek_on_empty_playlist_updates_position(self): + self.playback.seek(0) + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_seek_when_stopped_triggers_play(self): + self.playback.seek(0) + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @populate_tracklist + def test_seek_when_playing(self): + self.playback.play() + result = self.playback.seek(self.tracks[0].length - 1000) + self.assert_(result, 'Seek return value was %s' % result) + + @populate_tracklist + def test_seek_when_playing_updates_position(self): + length = self.tracklist.tracks[0].length + self.playback.play() + self.playback.seek(length - 1000) + position = self.playback.time_position + self.assertGreaterEqual(position, length - 1010) + + @populate_tracklist + def test_seek_when_paused(self): + self.playback.play() + self.playback.pause() + result = self.playback.seek(self.tracks[0].length - 1000) + self.assert_(result, 'Seek return value was %s' % result) + + @populate_tracklist + def test_seek_when_paused_updates_position(self): + length = self.tracklist.tracks[0].length + self.playback.play() + self.playback.pause() + self.playback.seek(length - 1000) + position = self.playback.time_position + self.assertGreaterEqual(position, length - 1010) + + @populate_tracklist + def test_seek_when_paused_triggers_play(self): + self.playback.play() + self.playback.pause() + self.playback.seek(0) + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @unittest.SkipTest + @populate_tracklist + def test_seek_beyond_end_of_song(self): + # FIXME need to decide return value + self.playback.play() + result = self.playback.seek(self.tracks[0].length * 100) + self.assert_(not result, 'Seek return value was %s' % result) + + @populate_tracklist + def test_seek_beyond_end_of_song_jumps_to_next_song(self): + self.playback.play() + self.playback.seek(self.tracks[0].length * 100) + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_seek_beyond_end_of_song_for_last_track(self): + self.playback.play(self.tracklist.tl_tracks[-1]) + self.playback.seek(self.tracklist.tracks[-1].length * 100) + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @unittest.SkipTest + @populate_tracklist + def test_seek_beyond_start_of_song(self): + # FIXME need to decide return value + self.playback.play() + result = self.playback.seek(-1000) + self.assert_(not result, 'Seek return value was %s' % result) + + @populate_tracklist + def test_seek_beyond_start_of_song_update_postion(self): + self.playback.play() + self.playback.seek(-1000) + position = self.playback.time_position + self.assertGreaterEqual(position, 0) + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @populate_tracklist + def test_stop_when_stopped(self): + self.playback.stop() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_stop_when_playing(self): + self.playback.play() + self.playback.stop() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + @populate_tracklist + def test_stop_when_paused(self): + self.playback.play() + self.playback.pause() + self.playback.stop() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + def test_stop_return_value(self): + self.playback.play() + self.assertEqual(self.playback.stop(), None) + + def test_time_position_when_stopped(self): + future = mock.Mock() + future.get = mock.Mock(return_value=0) + self.audio.get_position = mock.Mock(return_value=future) + + self.assertEqual(self.playback.time_position, 0) + + @populate_tracklist + def test_time_position_when_stopped_with_playlist(self): + future = mock.Mock() + future.get = mock.Mock(return_value=0) + self.audio.get_position = mock.Mock(return_value=future) + + self.assertEqual(self.playback.time_position, 0) + + @unittest.SkipTest # Uses sleep and does might not work with LocalBackend + @populate_tracklist + def test_time_position_when_playing(self): + self.playback.play() + first = self.playback.time_position + time.sleep(1) + second = self.playback.time_position + self.assertGreater(second, first) + + @unittest.SkipTest # Uses sleep + @populate_tracklist + def test_time_position_when_paused(self): + self.playback.play() + time.sleep(0.2) + self.playback.pause() + time.sleep(0.2) + first = self.playback.time_position + second = self.playback.time_position + self.assertEqual(first, second) + + @populate_tracklist + def test_play_with_consume(self): + self.playback.consume = True + self.playback.play() + self.assertEqual(self.playback.current_track, self.tracks[0]) + + @populate_tracklist + def test_playlist_is_empty_after_all_tracks_are_played_with_consume(self): + self.playback.consume = True + self.playback.play() + for _ in range(len(self.tracklist.tracks)): + self.playback.on_end_of_track() + self.assertEqual(len(self.tracklist.tracks), 0) + + @populate_tracklist + def test_play_with_random(self): + random.seed(1) + self.playback.random = True + self.playback.play() + self.assertEqual(self.playback.current_track, self.tracks[2]) + + @populate_tracklist + def test_previous_with_random(self): + random.seed(1) + self.playback.random = True + self.playback.play() + self.playback.next() + current_track = self.playback.current_track + self.playback.previous() + self.assertEqual(self.playback.current_track, current_track) + + @populate_tracklist + def test_end_of_song_starts_next_track(self): + self.playback.play() + self.playback.on_end_of_track() + self.assertEqual(self.playback.current_track, self.tracks[1]) + + @populate_tracklist + def test_end_of_song_with_single_and_repeat_starts_same(self): + self.playback.single = True + self.playback.repeat = True + self.playback.play() + self.playback.on_end_of_track() + self.assertEqual(self.playback.current_track, self.tracks[0]) + + @populate_tracklist + def test_end_of_playlist_stops(self): + self.playback.play(self.tracklist.tl_tracks[-1]) + self.playback.on_end_of_track() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + def test_repeat_off_by_default(self): + self.assertEqual(self.playback.repeat, False) + + def test_random_off_by_default(self): + self.assertEqual(self.playback.random, False) + + def test_consume_off_by_default(self): + self.assertEqual(self.playback.consume, False) + + @populate_tracklist + def test_random_until_end_of_playlist(self): + self.playback.random = True + self.playback.play() + for _ in self.tracks[1:]: + self.playback.next() + self.assertEqual(self.playback.tl_track_at_next, None) + + @populate_tracklist + def test_random_until_end_of_playlist_and_play_from_start(self): + self.playback.repeat = True + for _ in self.tracks: + self.playback.next() + self.assertNotEqual(self.playback.tl_track_at_next, None) + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + + @populate_tracklist + def test_random_until_end_of_playlist_with_repeat(self): + self.playback.repeat = True + self.playback.random = True + self.playback.play() + for _ in self.tracks: + self.playback.next() + self.assertNotEqual(self.playback.tl_track_at_next, None) + + @populate_tracklist + def test_played_track_during_random_not_played_again(self): + self.playback.random = True + self.playback.play() + played = [] + for _ in self.tracks: + self.assertNotIn(self.playback.current_track, played) + played.append(self.playback.current_track) + self.playback.next() + + @populate_tracklist + def test_playing_track_that_isnt_in_playlist(self): + test = lambda: self.playback.play((17, Track())) + self.assertRaises(AssertionError, test) diff --git a/tests/backends/local/playlists_test.py b/tests/backends/local/playlists_test.py index d405e8877b..4975d8aaff 100644 --- a/tests/backends/local/playlists_test.py +++ b/tests/backends/local/playlists_test.py @@ -5,18 +5,17 @@ import tempfile import unittest +import pykka + +from mopidy import audio, core from mopidy.backends.local import actor -from mopidy.models import Track +from mopidy.models import Playlist, Track from tests import path_to_data_dir -from tests.backends.base.playlists import ( - PlaylistsControllerTest) from tests.backends.local import generate_song -class LocalPlaylistsControllerTest( - PlaylistsControllerTest, unittest.TestCase): - +class LocalPlaylistsControllerTest(unittest.TestCase): backend_class = actor.LocalBackend config = { 'local': { @@ -29,10 +28,13 @@ def setUp(self): self.config['local']['playlists_dir'] = tempfile.mkdtemp() self.playlists_dir = self.config['local']['playlists_dir'] - super(LocalPlaylistsControllerTest, self).setUp() + self.audio = audio.DummyAudio.start().proxy() + self.backend = actor.LocalBackend.start( + config=self.config, audio=self.audio).proxy() + self.core = core.Core(backends=[self.backend]) def tearDown(self): - super(LocalPlaylistsControllerTest, self).tearDown() + pykka.ActorRegistry.stop_all() if os.path.exists(self.playlists_dir): shutil.rmtree(self.playlists_dir) @@ -121,3 +123,84 @@ def test_santitising_of_playlist_filenames(self): @unittest.SkipTest def test_playlist_dir_is_created(self): pass + + def test_create_returns_playlist_with_name_set(self): + playlist = self.core.playlists.create('test') + self.assertEqual(playlist.name, 'test') + + def test_create_returns_playlist_with_uri_set(self): + playlist = self.core.playlists.create('test') + self.assert_(playlist.uri) + + def test_create_adds_playlist_to_playlists_collection(self): + playlist = self.core.playlists.create('test') + self.assert_(self.core.playlists.playlists) + self.assertIn(playlist, self.core.playlists.playlists) + + def test_playlists_empty_to_start_with(self): + self.assert_(not self.core.playlists.playlists) + + def test_delete_non_existant_playlist(self): + self.core.playlists.delete('file:///unknown/playlist') + + def test_delete_playlist_removes_it_from_the_collection(self): + playlist = self.core.playlists.create('test') + self.assertIn(playlist, self.core.playlists.playlists) + + self.core.playlists.delete(playlist.uri) + + self.assertNotIn(playlist, self.core.playlists.playlists) + + def test_filter_without_criteria(self): + self.assertEqual( + self.core.playlists.playlists, self.core.playlists.filter()) + + def test_filter_with_wrong_criteria(self): + self.assertEqual([], self.core.playlists.filter(name='foo')) + + def test_filter_with_right_criteria(self): + playlist = self.core.playlists.create('test') + playlists = self.core.playlists.filter(name='test') + self.assertEqual([playlist], playlists) + + def test_filter_by_name_returns_single_match(self): + playlist = Playlist(name='b') + self.backend.playlists.playlists = [Playlist(name='a'), playlist] + self.assertEqual([playlist], self.core.playlists.filter(name='b')) + + def test_filter_by_name_returns_multiple_matches(self): + playlist = Playlist(name='b') + self.backend.playlists.playlists = [ + playlist, Playlist(name='a'), Playlist(name='b')] + playlists = self.core.playlists.filter(name='b') + self.assertIn(playlist, playlists) + self.assertEqual(2, len(playlists)) + + def test_filter_by_name_returns_no_matches(self): + self.backend.playlists.playlists = [ + Playlist(name='a'), Playlist(name='b')] + self.assertEqual([], self.core.playlists.filter(name='c')) + + def test_lookup_finds_playlist_by_uri(self): + original_playlist = self.core.playlists.create('test') + + looked_up_playlist = self.core.playlists.lookup(original_playlist.uri) + + self.assertEqual(original_playlist, looked_up_playlist) + + @unittest.SkipTest + def test_refresh(self): + pass + + def test_save_replaces_existing_playlist_with_updated_playlist(self): + playlist1 = self.core.playlists.create('test1') + self.assertIn(playlist1, self.core.playlists.playlists) + + playlist2 = playlist1.copy(name='test2') + playlist2 = self.core.playlists.save(playlist2) + self.assertNotIn(playlist1, self.core.playlists.playlists) + self.assertIn(playlist2, self.core.playlists.playlists) + + @unittest.SkipTest + def test_playlist_with_unknown_track(self): + pass diff --git a/tests/backends/local/tracklist_test.py b/tests/backends/local/tracklist_test.py index c7650ac065..1993d246c6 100644 --- a/tests/backends/local/tracklist_test.py +++ b/tests/backends/local/tracklist_test.py @@ -1,17 +1,20 @@ from __future__ import unicode_literals +import random import unittest +import pykka + +from mopidy import audio, core from mopidy.backends.local import actor -from mopidy.models import Track +from mopidy.core import PlaybackState +from mopidy.models import Playlist, TlTrack, Track from tests import path_to_data_dir -from tests.backends.base.tracklist import TracklistControllerTest -from tests.backends.local import generate_song +from tests.backends.local import generate_song, populate_tracklist -class LocalTracklistControllerTest(TracklistControllerTest, unittest.TestCase): - backend_class = actor.LocalBackend +class LocalTracklistControllerTest(unittest.TestCase): config = { 'local': { 'media_dir': path_to_data_dir(''), @@ -21,3 +24,282 @@ class LocalTracklistControllerTest(TracklistControllerTest, unittest.TestCase): } tracks = [ Track(uri=generate_song(i), length=4464) for i in range(1, 4)] + + def setUp(self): + self.audio = audio.DummyAudio.start().proxy() + self.backend = actor.LocalBackend.start( + config=self.config, audio=self.audio).proxy() + self.core = core.Core(audio=self.audio, backends=[self.backend]) + self.controller = self.core.tracklist + self.playback = self.core.playback + + assert len(self.tracks) == 3, 'Need three tracks to run tests.' + + def tearDown(self): + pykka.ActorRegistry.stop_all() + + def test_length(self): + self.assertEqual(0, len(self.controller.tl_tracks)) + self.assertEqual(0, self.controller.length) + self.controller.add(self.tracks) + self.assertEqual(3, len(self.controller.tl_tracks)) + self.assertEqual(3, self.controller.length) + + def test_add(self): + for track in self.tracks: + tl_tracks = self.controller.add([track]) + self.assertEqual(track, self.controller.tracks[-1]) + self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1]) + self.assertEqual(track, tl_tracks[0].track) + + def test_add_at_position(self): + for track in self.tracks[:-1]: + tl_tracks = self.controller.add([track], 0) + self.assertEqual(track, self.controller.tracks[0]) + self.assertEqual(tl_tracks[0], self.controller.tl_tracks[0]) + self.assertEqual(track, tl_tracks[0].track) + + @populate_tracklist + def test_add_at_position_outside_of_playlist(self): + for track in self.tracks: + tl_tracks = self.controller.add([track], len(self.tracks) + 2) + self.assertEqual(track, self.controller.tracks[-1]) + self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1]) + self.assertEqual(track, tl_tracks[0].track) + + @populate_tracklist + def test_filter_by_tlid(self): + tl_track = self.controller.tl_tracks[1] + self.assertEqual( + [tl_track], self.controller.filter(tlid=tl_track.tlid)) + + @populate_tracklist + def test_filter_by_uri(self): + tl_track = self.controller.tl_tracks[1] + self.assertEqual( + [tl_track], self.controller.filter(uri=tl_track.track.uri)) + + @populate_tracklist + def test_filter_by_uri_returns_nothing_for_invalid_uri(self): + self.assertEqual([], self.controller.filter(uri='foobar')) + + def test_filter_by_uri_returns_single_match(self): + track = Track(uri='a') + self.controller.add([Track(uri='z'), track, Track(uri='y')]) + self.assertEqual(track, self.controller.filter(uri='a')[0].track) + + def test_filter_by_uri_returns_multiple_matches(self): + track = Track(uri='a') + self.controller.add([Track(uri='z'), track, track]) + tl_tracks = self.controller.filter(uri='a') + self.assertEqual(track, tl_tracks[0].track) + self.assertEqual(track, tl_tracks[1].track) + + def test_filter_by_uri_returns_nothing_if_no_match(self): + self.controller.playlist = Playlist( + tracks=[Track(uri='z'), Track(uri='y')]) + self.assertEqual([], self.controller.filter(uri='a')) + + def test_filter_by_multiple_criteria_returns_elements_matching_all(self): + track1 = Track(uri='a', name='x') + track2 = Track(uri='b', name='x') + track3 = Track(uri='b', name='y') + self.controller.add([track1, track2, track3]) + self.assertEqual( + track1, self.controller.filter(uri='a', name='x')[0].track) + self.assertEqual( + track2, self.controller.filter(uri='b', name='x')[0].track) + self.assertEqual( + track3, self.controller.filter(uri='b', name='y')[0].track) + + def test_filter_by_criteria_that_is_not_present_in_all_elements(self): + track1 = Track() + track2 = Track(uri='b') + track3 = Track() + self.controller.add([track1, track2, track3]) + self.assertEqual(track2, self.controller.filter(uri='b')[0].track) + + @populate_tracklist + def test_clear(self): + self.controller.clear() + self.assertEqual(len(self.controller.tracks), 0) + + def test_clear_empty_playlist(self): + self.controller.clear() + self.assertEqual(len(self.controller.tracks), 0) + + @populate_tracklist + def test_clear_when_playing(self): + self.playback.play() + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.controller.clear() + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + + def test_add_appends_to_the_tracklist(self): + self.controller.add([Track(uri='a'), Track(uri='b')]) + self.assertEqual(len(self.controller.tracks), 2) + self.controller.add([Track(uri='c'), Track(uri='d')]) + self.assertEqual(len(self.controller.tracks), 4) + self.assertEqual(self.controller.tracks[0].uri, 'a') + self.assertEqual(self.controller.tracks[1].uri, 'b') + self.assertEqual(self.controller.tracks[2].uri, 'c') + self.assertEqual(self.controller.tracks[3].uri, 'd') + + def test_add_does_not_reset_version(self): + version = self.controller.version + self.controller.add([]) + self.assertEqual(self.controller.version, version) + + @populate_tracklist + def test_add_preserves_playing_state(self): + self.playback.play() + track = self.playback.current_track + self.controller.add(self.controller.tracks[1:2]) + self.assertEqual(self.playback.state, PlaybackState.PLAYING) + self.assertEqual(self.playback.current_track, track) + + @populate_tracklist + def test_add_preserves_stopped_state(self): + self.controller.add(self.controller.tracks[1:2]) + self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.assertEqual(self.playback.current_track, None) + + @populate_tracklist + def test_add_returns_the_tl_tracks_that_was_added(self): + tl_tracks = self.controller.add(self.controller.tracks[1:2]) + self.assertEqual(tl_tracks[0].track, self.controller.tracks[1]) + + def test_index_returns_index_of_track(self): + tl_tracks = self.controller.add(self.tracks) + self.assertEquals(0, self.controller.index(tl_tracks[0])) + self.assertEquals(1, self.controller.index(tl_tracks[1])) + self.assertEquals(2, self.controller.index(tl_tracks[2])) + + def test_index_raises_value_error_if_item_not_found(self): + test = lambda: self.controller.index(TlTrack(0, Track())) + self.assertRaises(ValueError, test) + + @populate_tracklist + def test_move_single(self): + self.controller.move(0, 0, 2) + + tracks = self.controller.tracks + self.assertEqual(tracks[2], self.tracks[0]) + + @populate_tracklist + def test_move_group(self): + self.controller.move(0, 2, 1) + + tracks = self.controller.tracks + self.assertEqual(tracks[1], self.tracks[0]) + self.assertEqual(tracks[2], self.tracks[1]) + + @populate_tracklist + def test_moving_track_outside_of_playlist(self): + tracks = len(self.controller.tracks) + test = lambda: self.controller.move(0, 0, tracks + 5) + self.assertRaises(AssertionError, test) + + @populate_tracklist + def test_move_group_outside_of_playlist(self): + tracks = len(self.controller.tracks) + test = lambda: self.controller.move(0, 2, tracks + 5) + self.assertRaises(AssertionError, test) + + @populate_tracklist + def test_move_group_out_of_range(self): + tracks = len(self.controller.tracks) + test = lambda: self.controller.move(tracks + 2, tracks + 3, 0) + self.assertRaises(AssertionError, test) + + @populate_tracklist + def test_move_group_invalid_group(self): + test = lambda: self.controller.move(2, 1, 0) + self.assertRaises(AssertionError, test) + + def test_tracks_attribute_is_immutable(self): + tracks1 = self.controller.tracks + tracks2 = self.controller.tracks + self.assertNotEqual(id(tracks1), id(tracks2)) + + @populate_tracklist + def test_remove(self): + track1 = self.controller.tracks[1] + track2 = self.controller.tracks[2] + version = self.controller.version + self.controller.remove(uri=track1.uri) + self.assertLess(version, self.controller.version) + self.assertNotIn(track1, self.controller.tracks) + self.assertEqual(track2, self.controller.tracks[1]) + + @populate_tracklist + def test_removing_track_that_does_not_exist_does_nothing(self): + self.controller.remove(uri='/nonexistant') + + def test_removing_from_empty_playlist_does_nothing(self): + self.controller.remove(uri='/nonexistant') + + @populate_tracklist + def test_shuffle(self): + random.seed(1) + self.controller.shuffle() + + shuffled_tracks = self.controller.tracks + + self.assertNotEqual(self.tracks, shuffled_tracks) + self.assertEqual(set(self.tracks), set(shuffled_tracks)) + + @populate_tracklist + def test_shuffle_subset(self): + random.seed(1) + self.controller.shuffle(1, 3) + + shuffled_tracks = self.controller.tracks + + self.assertNotEqual(self.tracks, shuffled_tracks) + self.assertEqual(self.tracks[0], shuffled_tracks[0]) + self.assertEqual(set(self.tracks), set(shuffled_tracks)) + + @populate_tracklist + def test_shuffle_invalid_subset(self): + test = lambda: self.controller.shuffle(3, 1) + self.assertRaises(AssertionError, test) + + @populate_tracklist + def test_shuffle_superset(self): + tracks = len(self.controller.tracks) + test = lambda: self.controller.shuffle(1, tracks + 5) + self.assertRaises(AssertionError, test) + + @populate_tracklist + def test_shuffle_open_subset(self): + random.seed(1) + self.controller.shuffle(1) + + shuffled_tracks = self.controller.tracks + + self.assertNotEqual(self.tracks, shuffled_tracks) + self.assertEqual(self.tracks[0], shuffled_tracks[0]) + self.assertEqual(set(self.tracks), set(shuffled_tracks)) + + @populate_tracklist + def test_slice_returns_a_subset_of_tracks(self): + track_slice = self.controller.slice(1, 3) + self.assertEqual(2, len(track_slice)) + self.assertEqual(self.tracks[1], track_slice[0].track) + self.assertEqual(self.tracks[2], track_slice[1].track) + + @populate_tracklist + def test_slice_returns_empty_list_if_indexes_outside_tracks_list(self): + self.assertEqual(0, len(self.controller.slice(7, 8))) + self.assertEqual(0, len(self.controller.slice(-1, 1))) + + def test_version_does_not_change_when_adding_nothing(self): + version = self.controller.version + self.controller.add([]) + self.assertEquals(version, self.controller.version) + + def test_version_increases_when_adding_something(self): + version = self.controller.version + self.controller.add([Track()]) + self.assertLess(version, self.controller.version)