Add unit tests for export/restore core state
Fix issues shown by test code
This commit is contained in:
parent
a5a9178b06
commit
e56c39ee78
@ -138,18 +138,19 @@ class Core(
|
|||||||
def on_start(self):
|
def on_start(self):
|
||||||
logger.debug("core on_start")
|
logger.debug("core on_start")
|
||||||
try:
|
try:
|
||||||
amount = self._config['core']['restore_state']
|
|
||||||
coverage = []
|
coverage = []
|
||||||
if not amount or 'off' == amount:
|
if self._config and 'restore_state' in self._config['core']:
|
||||||
pass
|
amount = self._config['core']['restore_state']
|
||||||
elif 'load' == amount:
|
if not amount or 'off' == amount:
|
||||||
coverage = ['tracklist', 'mode', 'volume', 'history']
|
pass
|
||||||
elif 'play' == amount:
|
elif 'load' == amount:
|
||||||
coverage = ['tracklist', 'mode', 'autoplay', 'volume',
|
coverage = ['tracklist', 'mode', 'volume', 'history']
|
||||||
'history']
|
elif 'play' == amount:
|
||||||
else:
|
coverage = ['tracklist', 'mode', 'autoplay', 'volume',
|
||||||
logger.warn('Unknown value for config '
|
'history']
|
||||||
'core.restore_state: %s', amount)
|
else:
|
||||||
|
logger.warn('Unknown value for config '
|
||||||
|
'core.restore_state: %s', amount)
|
||||||
if len(coverage):
|
if len(coverage):
|
||||||
self.load_state('persistent', coverage)
|
self.load_state('persistent', coverage)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -159,9 +160,10 @@ class Core(
|
|||||||
def on_stop(self):
|
def on_stop(self):
|
||||||
logger.debug("core on_stop")
|
logger.debug("core on_stop")
|
||||||
try:
|
try:
|
||||||
amount = self._config['core']['restore_state']
|
if self._config and 'restore_state' in self._config['core']:
|
||||||
if amount and 'off' != amount:
|
amount = self._config['core']['restore_state']
|
||||||
self.save_state('persistent')
|
if amount and 'off' != amount:
|
||||||
|
self.save_state('persistent')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn('on_stop: Unexpected error: %s', str(e))
|
logger.warn('on_stop: Unexpected error: %s', str(e))
|
||||||
pykka.ThreadingActor.on_stop(self)
|
pykka.ThreadingActor.on_stop(self)
|
||||||
@ -183,10 +185,10 @@ class Core(
|
|||||||
logger.info('Save state to "%s"', file_name)
|
logger.info('Save state to "%s"', file_name)
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
self.tracklist._state_export(data)
|
data['tracklist'] = self.tracklist._export_state()
|
||||||
self.history._state_export(data)
|
data['history'] = self.history._export_state()
|
||||||
self.playback._state_export(data)
|
data['playback'] = self.playback._export_state()
|
||||||
self.mixer._state_export(data)
|
data['mixer'] = self.mixer._export_state()
|
||||||
storage.save(file_name, data)
|
storage.save(file_name, data)
|
||||||
|
|
||||||
def load_state(self, name, coverage):
|
def load_state(self, name, coverage):
|
||||||
@ -217,11 +219,15 @@ class Core(
|
|||||||
file_name += '.state'
|
file_name += '.state'
|
||||||
|
|
||||||
data = storage.load(file_name)
|
data = storage.load(file_name)
|
||||||
self.history._state_import(data, coverage)
|
if 'history' in data:
|
||||||
self.tracklist._state_import(data, coverage)
|
self.history._restore_state(data['history'], coverage)
|
||||||
self.playback._state_import(data, coverage)
|
if 'tracklist' in data:
|
||||||
self.mixer._state_import(data, coverage)
|
self.tracklist._restore_state(data['tracklist'], coverage)
|
||||||
logger.info('Load state done')
|
if 'playback' in data:
|
||||||
|
self.playback._restore_state(data['playback'], coverage)
|
||||||
|
if 'mixer' in data:
|
||||||
|
self.mixer._restore_state(data['mixer'], coverage)
|
||||||
|
logger.debug('Load state done. file_name="%s"', file_name)
|
||||||
|
|
||||||
|
|
||||||
class Backends(list):
|
class Backends(list):
|
||||||
|
|||||||
@ -58,19 +58,20 @@ class HistoryController(object):
|
|||||||
"""
|
"""
|
||||||
return copy.copy(self._history)
|
return copy.copy(self._history)
|
||||||
|
|
||||||
def _state_export(self, data):
|
def _export_state(self):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
history_list = []
|
history_list = []
|
||||||
for timestamp, track in self._history:
|
for timestamp, track in self._history:
|
||||||
history_list.append(models.HistoryTrack(
|
history_list.append(models.HistoryTrack(
|
||||||
timestamp=timestamp, track=track))
|
timestamp=timestamp, track=track))
|
||||||
data['history'] = models.HistoryState(history=history_list)
|
return models.HistoryState(history=history_list)
|
||||||
|
|
||||||
def _state_import(self, data, coverage):
|
def _restore_state(self, state, coverage):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
if 'history' in data:
|
if state:
|
||||||
hstate = data['history']
|
if not isinstance(state, models.HistoryState):
|
||||||
|
raise TypeError('Expect an argument of type "HistoryState"')
|
||||||
if 'history' in coverage:
|
if 'history' in coverage:
|
||||||
self._history = []
|
self._history = []
|
||||||
for htrack in hstate.history:
|
for htrack in state.history:
|
||||||
self._history.append((htrack.timestamp, htrack.track))
|
self._history.append((htrack.timestamp, htrack.track))
|
||||||
|
|||||||
@ -101,13 +101,15 @@ class MixerController(object):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _state_export(self, data):
|
def _export_state(self):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
data['mixer'] = MixerState(volume=self.get_volume())
|
return MixerState(volume=self.get_volume())
|
||||||
|
|
||||||
def _state_import(self, data, coverage):
|
def _restore_state(self, state, coverage):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
if 'mixer' in data:
|
if state:
|
||||||
ms = data['mixer']
|
if not isinstance(state, MixerState):
|
||||||
|
raise TypeError('Expect an argument of type "MixerState"')
|
||||||
if 'volume' in coverage:
|
if 'volume' in coverage:
|
||||||
self.set_volume(ms.volume)
|
if state.volume:
|
||||||
|
self.set_volume(state.volume)
|
||||||
|
|||||||
@ -524,20 +524,19 @@ class PlaybackController(object):
|
|||||||
logger.debug('Triggering seeked event')
|
logger.debug('Triggering seeked event')
|
||||||
listener.CoreListener.send('seeked', time_position=time_position)
|
listener.CoreListener.send('seeked', time_position=time_position)
|
||||||
|
|
||||||
def _state_export(self, data):
|
def _export_state(self):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
data['playback'] = models.PlaybackState(
|
return models.PlaybackState(
|
||||||
tl_track=self.get_current_tl_track(),
|
tl_track=self.get_current_tl_track(),
|
||||||
position=self.get_time_position(),
|
position=self.get_time_position(),
|
||||||
state=self.get_state())
|
state=self.get_state())
|
||||||
|
|
||||||
def _state_import(self, data, coverage):
|
def _restore_state(self, state, coverage):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
if 'playback' in data:
|
if state:
|
||||||
ps = data['playback']
|
if not isinstance(state, models.PlaybackState):
|
||||||
|
raise TypeError('Expect an argument of type "PlaybackState"')
|
||||||
if 'autoplay' in coverage:
|
if 'autoplay' in coverage:
|
||||||
tl_track = ps.tl_track
|
if state.tl_track is not None:
|
||||||
if tl_track is not None:
|
self.play(tl_track=state.tl_track)
|
||||||
self.play(tl_track=tl_track)
|
# TODO: seek to state.position?
|
||||||
# TODO: Seek not working. It seeks to early.
|
|
||||||
# self.seek(ps.position)
|
|
||||||
|
|||||||
@ -645,9 +645,9 @@ class TracklistController(object):
|
|||||||
logger.debug('Triggering options changed event')
|
logger.debug('Triggering options changed event')
|
||||||
listener.CoreListener.send('options_changed')
|
listener.CoreListener.send('options_changed')
|
||||||
|
|
||||||
def _state_export(self, data):
|
def _export_state(self):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
data['tracklist'] = TracklistState(
|
return TracklistState(
|
||||||
tracks=self._tl_tracks,
|
tracks=self._tl_tracks,
|
||||||
next_tlid=self._next_tlid,
|
next_tlid=self._next_tlid,
|
||||||
consume=self.get_consume(),
|
consume=self.get_consume(),
|
||||||
@ -655,19 +655,20 @@ class TracklistController(object):
|
|||||||
repeat=self.get_repeat(),
|
repeat=self.get_repeat(),
|
||||||
single=self.get_single())
|
single=self.get_single())
|
||||||
|
|
||||||
def _state_import(self, data, coverage):
|
def _restore_state(self, state, coverage):
|
||||||
"""Internal method for :class:`mopidy.Core`."""
|
"""Internal method for :class:`mopidy.Core`."""
|
||||||
if 'tracklist' in data:
|
if state:
|
||||||
tls = data['tracklist']
|
if not isinstance(state, TracklistState):
|
||||||
|
raise TypeError('Expect an argument of type "TracklistState"')
|
||||||
if 'mode' in coverage:
|
if 'mode' in coverage:
|
||||||
self.set_consume(tls.consume)
|
self.set_consume(state.consume)
|
||||||
self.set_random(tls.random)
|
self.set_random(state.random)
|
||||||
self.set_repeat(tls.repeat)
|
self.set_repeat(state.repeat)
|
||||||
self.set_single(tls.single)
|
self.set_single(state.single)
|
||||||
if 'tracklist' in coverage:
|
if 'tracklist' in coverage:
|
||||||
if tls.next_tlid > self._next_tlid:
|
if state.next_tlid > self._next_tlid:
|
||||||
self._next_tlid = tls.next_tlid
|
self._next_tlid = state.next_tlid
|
||||||
self._tl_tracks = []
|
self._tl_tracks = []
|
||||||
for track in tls.tracks:
|
for track in state.tracks:
|
||||||
self._tl_tracks.append(track)
|
self._tl_tracks.append(track)
|
||||||
self._trigger_tracklist_changed()
|
self._trigger_tracklist_changed()
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
@ -43,3 +45,29 @@ class CoreActorTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_version(self):
|
def test_version(self):
|
||||||
self.assertEqual(self.core.version, versioning.get_version())
|
self.assertEqual(self.core.version, versioning.get_version())
|
||||||
|
|
||||||
|
|
||||||
|
class CoreActorExportRestoreTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.temp_dir = tempfile.mkdtemp()
|
||||||
|
config = {
|
||||||
|
'core': {
|
||||||
|
'max_tracklist_length': 10000,
|
||||||
|
'restore_state': 'play',
|
||||||
|
'data_dir': self.temp_dir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.core = Core.start(
|
||||||
|
config=config, mixer=None, backends=[]).proxy()
|
||||||
|
|
||||||
|
def tearDown(self): # noqa: N802
|
||||||
|
pykka.ActorRegistry.stop_all()
|
||||||
|
shutil.rmtree(self.temp_dir)
|
||||||
|
|
||||||
|
def test_restore_on_start(self):
|
||||||
|
# cover mopidy.core.actor.on_start and .on_stop
|
||||||
|
# starting the actor by calling any function:
|
||||||
|
self.core.get_version()
|
||||||
|
pass
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import unittest
|
|||||||
|
|
||||||
from mopidy import compat
|
from mopidy import compat
|
||||||
from mopidy.core import HistoryController
|
from mopidy.core import HistoryController
|
||||||
from mopidy.models import Artist, Track
|
from mopidy.models import Artist, HistoryState, HistoryTrack, Ref, Track
|
||||||
|
|
||||||
|
|
||||||
class PlaybackHistoryTest(unittest.TestCase):
|
class PlaybackHistoryTest(unittest.TestCase):
|
||||||
@ -46,3 +46,60 @@ class PlaybackHistoryTest(unittest.TestCase):
|
|||||||
self.assertIn(track.name, ref.name)
|
self.assertIn(track.name, ref.name)
|
||||||
for artist in track.artists:
|
for artist in track.artists:
|
||||||
self.assertIn(artist.name, ref.name)
|
self.assertIn(artist.name, ref.name)
|
||||||
|
|
||||||
|
|
||||||
|
class CoreHistoryExportRestoreTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self): # noqa: N802
|
||||||
|
self.tracks = [
|
||||||
|
Track(uri='dummy1:a', name='foober'),
|
||||||
|
Track(uri='dummy2:a', name='foo'),
|
||||||
|
Track(uri='dummy3:a', name='bar')
|
||||||
|
]
|
||||||
|
|
||||||
|
self.refs = []
|
||||||
|
for t in self.tracks:
|
||||||
|
self.refs.append(Ref.track(uri=t.uri, name=t.name))
|
||||||
|
|
||||||
|
self.history = HistoryController()
|
||||||
|
|
||||||
|
def test_export(self):
|
||||||
|
self.history._add_track(self.tracks[2])
|
||||||
|
self.history._add_track(self.tracks[1])
|
||||||
|
|
||||||
|
value = self.history._export_state()
|
||||||
|
|
||||||
|
self.assertEqual(len(value.history), 2)
|
||||||
|
# last in, first out
|
||||||
|
self.assertEqual(value.history[0].track, self.refs[1])
|
||||||
|
self.assertEqual(value.history[1].track, self.refs[2])
|
||||||
|
|
||||||
|
def test_import(self):
|
||||||
|
state = HistoryState(history=[
|
||||||
|
HistoryTrack(timestamp=34, track=self.refs[0]),
|
||||||
|
HistoryTrack(timestamp=45, track=self.refs[2]),
|
||||||
|
HistoryTrack(timestamp=56, track=self.refs[1])])
|
||||||
|
coverage = ['history']
|
||||||
|
self.history._restore_state(state, coverage)
|
||||||
|
|
||||||
|
hist = self.history.get_history()
|
||||||
|
self.assertEqual(len(hist), 3)
|
||||||
|
self.assertEqual(hist[0], (34, self.refs[0]))
|
||||||
|
self.assertEqual(hist[1], (45, self.refs[2]))
|
||||||
|
self.assertEqual(hist[2], (56, self.refs[1]))
|
||||||
|
|
||||||
|
# after import, adding more tracks must be possible
|
||||||
|
self.history._add_track(self.tracks[1])
|
||||||
|
hist = self.history.get_history()
|
||||||
|
self.assertEqual(len(hist), 4)
|
||||||
|
self.assertEqual(hist[0][1], self.refs[1])
|
||||||
|
self.assertEqual(hist[1], (34, self.refs[0]))
|
||||||
|
self.assertEqual(hist[2], (45, self.refs[2]))
|
||||||
|
self.assertEqual(hist[3], (56, self.refs[1]))
|
||||||
|
|
||||||
|
def test_import_invalid_type(self):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
self.history._restore_state(11, None)
|
||||||
|
|
||||||
|
def test_import_none(self):
|
||||||
|
self.history._restore_state(None, None)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import mock
|
|||||||
import pykka
|
import pykka
|
||||||
|
|
||||||
from mopidy import core, mixer
|
from mopidy import core, mixer
|
||||||
|
from mopidy.models import MixerState
|
||||||
from tests import dummy_mixer
|
from tests import dummy_mixer
|
||||||
|
|
||||||
|
|
||||||
@ -154,3 +155,39 @@ class SetMuteBadBackendTest(MockBackendCoreMixerBase):
|
|||||||
def test_backend_returns_wrong_type(self):
|
def test_backend_returns_wrong_type(self):
|
||||||
self.mixer.set_mute.return_value.get.return_value = 'done'
|
self.mixer.set_mute.return_value.get.return_value = 'done'
|
||||||
self.assertFalse(self.core.mixer.set_mute(True))
|
self.assertFalse(self.core.mixer.set_mute(True))
|
||||||
|
|
||||||
|
|
||||||
|
class CoreMixerExportRestoreTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self): # noqa: N802
|
||||||
|
self.mixer = dummy_mixer.create_proxy()
|
||||||
|
self.core = core.Core(mixer=self.mixer, backends=[])
|
||||||
|
|
||||||
|
def test_export(self):
|
||||||
|
volume = 32
|
||||||
|
target = MixerState(volume=volume)
|
||||||
|
self.core.mixer.set_volume(volume)
|
||||||
|
value = self.core.mixer._export_state()
|
||||||
|
self.assertEqual(target, value)
|
||||||
|
|
||||||
|
def test_import(self):
|
||||||
|
self.core.mixer.set_volume(11)
|
||||||
|
volume = 45
|
||||||
|
target = MixerState(volume=volume)
|
||||||
|
coverage = ['volume']
|
||||||
|
self.core.mixer._restore_state(target, coverage)
|
||||||
|
self.assertEqual(volume, self.core.mixer.get_volume())
|
||||||
|
|
||||||
|
def test_import_not_covered(self):
|
||||||
|
self.core.mixer.set_volume(21)
|
||||||
|
target = MixerState(volume=56)
|
||||||
|
coverage = ['other']
|
||||||
|
self.core.mixer._restore_state(target, coverage)
|
||||||
|
self.assertEqual(21, self.core.mixer.get_volume())
|
||||||
|
|
||||||
|
def test_import_invalid_type(self):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
self.core.mixer._restore_state(11, None)
|
||||||
|
|
||||||
|
def test_import_none(self):
|
||||||
|
self.core.mixer._restore_state(None, None)
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import pykka
|
|||||||
|
|
||||||
from mopidy import backend, core
|
from mopidy import backend, core
|
||||||
from mopidy.internal import deprecation
|
from mopidy.internal import deprecation
|
||||||
from mopidy.models import Track
|
from mopidy.models import PlaybackState, Track
|
||||||
|
|
||||||
from tests import dummy_audio
|
from tests import dummy_audio
|
||||||
|
|
||||||
@ -874,3 +874,59 @@ class Bug1177RegressionTest(unittest.TestCase):
|
|||||||
c.playback.pause()
|
c.playback.pause()
|
||||||
c.playback.next()
|
c.playback.next()
|
||||||
b.playback.change_track.assert_called_once_with(track2)
|
b.playback.change_track.assert_called_once_with(track2)
|
||||||
|
|
||||||
|
|
||||||
|
class CorePlaybackExportRestoreTest(BaseTest):
|
||||||
|
|
||||||
|
def test_export(self):
|
||||||
|
tl_tracks = self.core.tracklist.get_tl_tracks()
|
||||||
|
|
||||||
|
self.core.playback.play(tl_tracks[1])
|
||||||
|
self.replay_events()
|
||||||
|
|
||||||
|
state = PlaybackState(
|
||||||
|
position=0, state='playing', tl_track=tl_tracks[1])
|
||||||
|
value = self.core.playback._export_state()
|
||||||
|
|
||||||
|
self.assertEqual(state, value)
|
||||||
|
|
||||||
|
def test_import(self):
|
||||||
|
tl_tracks = self.core.tracklist.get_tl_tracks()
|
||||||
|
|
||||||
|
self.core.playback.stop()
|
||||||
|
self.replay_events()
|
||||||
|
self.assertEqual('stopped', self.core.playback.get_state())
|
||||||
|
|
||||||
|
state = PlaybackState(
|
||||||
|
position=0, state='playing', tl_track=tl_tracks[2])
|
||||||
|
coverage = ['autoplay']
|
||||||
|
self.core.playback._restore_state(state, coverage)
|
||||||
|
self.replay_events()
|
||||||
|
|
||||||
|
self.assertEqual('playing', self.core.playback.get_state())
|
||||||
|
self.assertEqual(tl_tracks[2],
|
||||||
|
self.core.playback.get_current_tl_track())
|
||||||
|
|
||||||
|
def test_import_not_covered(self):
|
||||||
|
tl_tracks = self.core.tracklist.get_tl_tracks()
|
||||||
|
|
||||||
|
self.core.playback.stop()
|
||||||
|
self.replay_events()
|
||||||
|
self.assertEqual('stopped', self.core.playback.get_state())
|
||||||
|
|
||||||
|
state = PlaybackState(
|
||||||
|
position=0, state='playing', tl_track=tl_tracks[2])
|
||||||
|
coverage = ['other']
|
||||||
|
self.core.playback._restore_state(state, coverage)
|
||||||
|
self.replay_events()
|
||||||
|
|
||||||
|
self.assertEqual('stopped', self.core.playback.get_state())
|
||||||
|
self.assertEqual(None,
|
||||||
|
self.core.playback.get_current_tl_track())
|
||||||
|
|
||||||
|
def test_import_invalid_type(self):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
self.core.playback._restore_state(11, None)
|
||||||
|
|
||||||
|
def test_import_none(self):
|
||||||
|
self.core.playback._restore_state(None, None)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import mock
|
|||||||
|
|
||||||
from mopidy import backend, core
|
from mopidy import backend, core
|
||||||
from mopidy.internal import deprecation
|
from mopidy.internal import deprecation
|
||||||
from mopidy.models import TlTrack, Track
|
from mopidy.models import TlTrack, Track, TracklistState
|
||||||
|
|
||||||
|
|
||||||
class TracklistTest(unittest.TestCase):
|
class TracklistTest(unittest.TestCase):
|
||||||
@ -177,3 +177,113 @@ class TracklistIndexTest(unittest.TestCase):
|
|||||||
self.assertEqual(0, self.core.tracklist.index())
|
self.assertEqual(0, self.core.tracklist.index())
|
||||||
self.assertEqual(1, self.core.tracklist.index())
|
self.assertEqual(1, self.core.tracklist.index())
|
||||||
self.assertEqual(2, self.core.tracklist.index())
|
self.assertEqual(2, self.core.tracklist.index())
|
||||||
|
|
||||||
|
|
||||||
|
class TracklistExportRestoreTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self): # noqa: N802
|
||||||
|
config = {
|
||||||
|
'core': {
|
||||||
|
'max_tracklist_length': 10000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tracks = [
|
||||||
|
Track(uri='dummy1:a', name='foo'),
|
||||||
|
Track(uri='dummy1:b', name='foo'),
|
||||||
|
Track(uri='dummy1:c', name='bar'),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.tl_tracks = [
|
||||||
|
TlTrack(tlid=4, track=Track(uri='first', name='First')),
|
||||||
|
TlTrack(tlid=5, track=Track(uri='second', name='Second')),
|
||||||
|
TlTrack(tlid=6, track=Track(uri='third', name='Third')),
|
||||||
|
TlTrack(tlid=8, track=Track(uri='last', name='Last'))
|
||||||
|
]
|
||||||
|
|
||||||
|
def lookup(uris):
|
||||||
|
return {u: [t for t in self.tracks if t.uri == u] for u in uris}
|
||||||
|
|
||||||
|
self.core = core.Core(config, mixer=None, backends=[])
|
||||||
|
self.core.library = mock.Mock(spec=core.LibraryController)
|
||||||
|
self.core.library.lookup.side_effect = lookup
|
||||||
|
|
||||||
|
self.core.playback = mock.Mock(spec=core.PlaybackController)
|
||||||
|
|
||||||
|
def test_export(self):
|
||||||
|
tl_tracks = self.core.tracklist.add(uris=[
|
||||||
|
t.uri for t in self.tracks])
|
||||||
|
consume = True
|
||||||
|
next_tlid = len(tl_tracks) + 1
|
||||||
|
self.core.tracklist.set_consume(consume)
|
||||||
|
target = TracklistState(consume=consume,
|
||||||
|
repeat=False,
|
||||||
|
single=False,
|
||||||
|
random=False,
|
||||||
|
next_tlid=next_tlid,
|
||||||
|
tracks=tl_tracks)
|
||||||
|
value = self.core.tracklist._export_state()
|
||||||
|
self.assertEqual(target, value)
|
||||||
|
|
||||||
|
def test_import(self):
|
||||||
|
target = TracklistState(consume=False,
|
||||||
|
repeat=True,
|
||||||
|
single=True,
|
||||||
|
random=False,
|
||||||
|
next_tlid=12,
|
||||||
|
tracks=self.tl_tracks)
|
||||||
|
coverage = ['mode', 'tracklist']
|
||||||
|
self.core.tracklist._restore_state(target, coverage)
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_consume())
|
||||||
|
self.assertEqual(True, self.core.tracklist.get_repeat())
|
||||||
|
self.assertEqual(True, self.core.tracklist.get_single())
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_random())
|
||||||
|
self.assertEqual(12, self.core.tracklist._next_tlid)
|
||||||
|
self.assertEqual(4, self.core.tracklist.get_length())
|
||||||
|
self.assertEqual(self.tl_tracks, self.core.tracklist.get_tl_tracks())
|
||||||
|
|
||||||
|
# after import, adding more tracks must be possible
|
||||||
|
self.core.tracklist.add(uris=[self.tracks[1].uri])
|
||||||
|
self.assertEqual(13, self.core.tracklist._next_tlid)
|
||||||
|
self.assertEqual(5, self.core.tracklist.get_length())
|
||||||
|
|
||||||
|
def test_import_mode_only(self):
|
||||||
|
target = TracklistState(consume=False,
|
||||||
|
repeat=True,
|
||||||
|
single=True,
|
||||||
|
random=False,
|
||||||
|
next_tlid=12,
|
||||||
|
tracks=self.tl_tracks)
|
||||||
|
coverage = ['mode']
|
||||||
|
self.core.tracklist._restore_state(target, coverage)
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_consume())
|
||||||
|
self.assertEqual(True, self.core.tracklist.get_repeat())
|
||||||
|
self.assertEqual(True, self.core.tracklist.get_single())
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_random())
|
||||||
|
self.assertEqual(1, self.core.tracklist._next_tlid)
|
||||||
|
self.assertEqual(0, self.core.tracklist.get_length())
|
||||||
|
self.assertEqual([], self.core.tracklist.get_tl_tracks())
|
||||||
|
|
||||||
|
def test_import_tracklist_only(self):
|
||||||
|
target = TracklistState(consume=False,
|
||||||
|
repeat=True,
|
||||||
|
single=True,
|
||||||
|
random=False,
|
||||||
|
next_tlid=12,
|
||||||
|
tracks=self.tl_tracks)
|
||||||
|
coverage = ['tracklist']
|
||||||
|
self.core.tracklist._restore_state(target, coverage)
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_consume())
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_repeat())
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_single())
|
||||||
|
self.assertEqual(False, self.core.tracklist.get_random())
|
||||||
|
self.assertEqual(12, self.core.tracklist._next_tlid)
|
||||||
|
self.assertEqual(4, self.core.tracklist.get_length())
|
||||||
|
self.assertEqual(self.tl_tracks, self.core.tracklist.get_tl_tracks())
|
||||||
|
|
||||||
|
def test_import_invalid_type(self):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
self.core.tracklist._restore_state(11, None)
|
||||||
|
|
||||||
|
def test_import_none(self):
|
||||||
|
self.core.tracklist._restore_state(None, None)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user