Anna Schumaker
55486c20c3
We need to do some bookkeeping inside the Playlist before notifying the Factory that a track has been requested. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
510 lines
20 KiB
Python
510 lines
20 KiB
Python
# Copyright 2023 (c) Anna Schumaker.
|
|
"""Tests our PlaylistModel."""
|
|
import pathlib
|
|
import unittest.mock
|
|
import tests.util
|
|
import emmental.playlist.playlist
|
|
from gi.repository import GObject
|
|
|
|
|
|
class TestPlaylist(tests.util.TestCase):
|
|
"""Tests the Playlist Gio.ListModel."""
|
|
|
|
def setUp(self):
|
|
"""Set up common variables."""
|
|
super().setUp()
|
|
self.db_plist = self.sql.playlists.create("Test Playlist")
|
|
self.playlist = emmental.playlist.playlist.Playlist(self.sql)
|
|
|
|
self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
|
|
self.album = self.sql.albums.create("Test Album", "Artist", "2023")
|
|
self.medium = self.sql.media.create(self.album, "", number=1)
|
|
self.year = self.sql.years.create(2023)
|
|
|
|
self.track1 = self.sql.tracks.create(self.library,
|
|
pathlib.Path("/a/b/1.ogg"),
|
|
self.medium, self.year,
|
|
number=1, length=10)
|
|
self.track2 = self.sql.tracks.create(self.library,
|
|
pathlib.Path("/a/b/2.ogg"),
|
|
self.medium, self.year,
|
|
number=2, length=20)
|
|
self.track3 = self.sql.tracks.create(self.library,
|
|
pathlib.Path("/a/b/3.ogg"),
|
|
self.medium, self.year,
|
|
number=3, length=30)
|
|
|
|
def test_property_flags(self):
|
|
"""Test the FLAGS constant."""
|
|
self.assertEqual(emmental.playlist.playlist.FLAGS,
|
|
GObject.ParamFlags.READWRITE |
|
|
GObject.ParamFlags.EXPLICIT_NOTIFY)
|
|
|
|
def test_init(self):
|
|
"""Test that the Playlist was set up correctly."""
|
|
self.assertIsInstance(self.playlist,
|
|
emmental.playlist.model.TrackidModel)
|
|
self.assertIsInstance(self.playlist._Playlist__picked,
|
|
emmental.db.tracks.TrackidSet)
|
|
|
|
self.assertEqual(self.playlist.sql, self.sql)
|
|
self.assertDictEqual(self.playlist._Playlist__sort_keys, {})
|
|
|
|
self.assertIsNone(self.playlist._Playlist__playlist)
|
|
self.assertIsNone(self.playlist._Playlist__sort_order)
|
|
|
|
plist2 = emmental.playlist.playlist.Playlist(self.sql, self.db_plist)
|
|
self.assertEqual(plist2.playlist, self.db_plist)
|
|
|
|
def test_can_go_next(self):
|
|
"""Test the playlist can_go_next() property."""
|
|
self.assertFalse(self.playlist.can_go_next)
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
self.playlist.add_track(self.track1)
|
|
self.assertTrue(self.playlist.can_go_next)
|
|
|
|
self.playlist.add_track(self.track2)
|
|
self.playlist.next_track()
|
|
self.assertTrue(self.playlist.can_go_next)
|
|
self.playlist.next_track()
|
|
self.assertFalse(self.playlist.can_go_next)
|
|
|
|
self.playlist.move_track_up(self.track2)
|
|
self.assertTrue(self.playlist.can_go_next)
|
|
self.playlist.move_track_down(self.track2)
|
|
self.assertFalse(self.playlist.can_go_next)
|
|
|
|
def test_add_track(self):
|
|
"""Test the playlist add_track() function."""
|
|
self.playlist.add_track(self.track1)
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
self.playlist.add_track(self.track1)
|
|
self.assertListEqual(self.playlist.trackids, [self.track1.trackid])
|
|
|
|
def test_index(self):
|
|
"""Test the playlist index() function."""
|
|
self.assertIsNone(self.playlist.index(self.track1))
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
self.playlist.add_track(self.track1)
|
|
|
|
self.assertEqual(self.playlist.index(self.track1), 0)
|
|
self.assertIsNone(self.playlist.index(self.track2))
|
|
self.assertIsNone(super(type(self.playlist), self.playlist).index(0))
|
|
self.assertIsNone(self.playlist.index(None))
|
|
|
|
def test_move_track_down(self):
|
|
"""Test the playlist move_track_down() function."""
|
|
self.playlist.move_track_down(self.track1)
|
|
|
|
self.db_plist.add_track(self.track1)
|
|
self.db_plist.add_track(self.track2)
|
|
self.db_plist.add_track(self.track3)
|
|
self.playlist.playlist = self.db_plist
|
|
|
|
items_changed = unittest.mock.Mock()
|
|
self.playlist.connect("items-changed", items_changed)
|
|
|
|
self.playlist.move_track_down(self.track2)
|
|
self.assertEqual(self.db_plist.sort_order, "user")
|
|
self.assertDictEqual(self.playlist._Playlist__sort_keys,
|
|
{self.track1.trackid: 0,
|
|
self.track3.trackid: 1,
|
|
self.track2.trackid: 2})
|
|
self.assertListEqual(self.playlist.trackids, [self.track1.trackid,
|
|
self.track3.trackid,
|
|
self.track2.trackid])
|
|
items_changed.assert_called_once_with(self.playlist, 0, 3, 3)
|
|
|
|
items_changed.reset_mock()
|
|
self.playlist.move_track_down(self.track1)
|
|
self.assertDictEqual(self.playlist._Playlist__sort_keys,
|
|
{self.track3.trackid: 0,
|
|
self.track1.trackid: 1,
|
|
self.track2.trackid: 2})
|
|
self.assertListEqual(self.playlist.trackids, [self.track3.trackid,
|
|
self.track1.trackid,
|
|
self.track2.trackid])
|
|
items_changed.assert_called_once_with(self.playlist, 0, 2, 2)
|
|
|
|
def test_move_track_up(self):
|
|
"""Test the playlist move_track_up() function."""
|
|
self.playlist.move_track_up(self.track1)
|
|
|
|
self.db_plist.add_track(self.track1)
|
|
self.db_plist.add_track(self.track2)
|
|
self.db_plist.add_track(self.track3)
|
|
self.playlist.playlist = self.db_plist
|
|
|
|
items_changed = unittest.mock.Mock()
|
|
self.playlist.connect("items-changed", items_changed)
|
|
|
|
self.playlist.move_track_up(self.track2)
|
|
self.assertEqual(self.db_plist.sort_order, "user")
|
|
self.assertDictEqual(self.playlist._Playlist__sort_keys,
|
|
{self.track2.trackid: 0,
|
|
self.track1.trackid: 1,
|
|
self.track3.trackid: 2})
|
|
self.assertListEqual(self.playlist.trackids, [self.track2.trackid,
|
|
self.track1.trackid,
|
|
self.track3.trackid])
|
|
items_changed.assert_called_once_with(self.playlist, 0, 3, 3)
|
|
|
|
items_changed.reset_mock()
|
|
self.playlist.move_track_up(self.track3)
|
|
self.assertDictEqual(self.playlist._Playlist__sort_keys,
|
|
{self.track2.trackid: 0,
|
|
self.track3.trackid: 1,
|
|
self.track1.trackid: 2})
|
|
self.assertListEqual(self.playlist.trackids, [self.track2.trackid,
|
|
self.track3.trackid,
|
|
self.track1.trackid])
|
|
items_changed.assert_called_once_with(self.playlist, 1, 2, 2)
|
|
|
|
def test_next_track(self):
|
|
"""Test the playlist next_track() function."""
|
|
self.assertIsNone(self.playlist.next_track())
|
|
|
|
def test_remove_track(self):
|
|
"""Test the playlist remove_track() function."""
|
|
self.playlist.remove_track(self.track1)
|
|
|
|
self.db_plist.add_track(self.track1)
|
|
self.playlist.playlist = self.db_plist
|
|
self.playlist.remove_track(self.track1)
|
|
self.assertListEqual(self.playlist.trackids, [])
|
|
|
|
def test_remove_current_track(self):
|
|
"""Test removing the current-track from the playlist."""
|
|
self.db_plist.add_track(self.track1)
|
|
self.db_plist.add_track(self.track2)
|
|
self.db_plist.add_track(self.track3)
|
|
self.playlist.playlist = self.db_plist
|
|
self.playlist.current_track = self.track2
|
|
|
|
notify = unittest.mock.Mock()
|
|
self.playlist.connect("notify::current-track", notify)
|
|
self.playlist.remove_track(self.track3)
|
|
notify.assert_not_called()
|
|
|
|
self.playlist.remove_track(self.track2)
|
|
self.assertEqual(self.playlist.current_track, self.track1)
|
|
self.assertEqual(self.db_plist.current_trackid, self.track1.trackid)
|
|
notify.assert_called()
|
|
|
|
notify.reset_mock()
|
|
self.playlist.remove_track(self.track1)
|
|
self.assertIsNone(self.playlist.current_track)
|
|
self.assertEqual(self.db_plist.current_trackid, 0)
|
|
notify.assert_called()
|
|
|
|
self.playlist.add_track(self.track1)
|
|
self.playlist.add_track(self.track3)
|
|
self.playlist.current_track = self.track3
|
|
|
|
notify.reset_mock()
|
|
self.db_plist.remove_track(self.track3)
|
|
self.assertEqual(self.playlist.current_track, self.track1)
|
|
self.assertEqual(self.db_plist.current_trackid, self.track1.trackid)
|
|
notify.assert_called()
|
|
|
|
def test_request_track(self):
|
|
"""Test the Playlist request_track() function."""
|
|
requested = unittest.mock.Mock()
|
|
self.playlist.connect("track-requested", requested)
|
|
|
|
self.playlist.request_track(self.track1)
|
|
requested.assert_not_called()
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
self.playlist.request_track(self.track1)
|
|
requested.assert_not_called()
|
|
|
|
self.db_plist.add_track(self.track1)
|
|
self.playlist.request_track(self.track1)
|
|
requested.assert_called_with(self.playlist, self.track1)
|
|
self.assertEqual(self.playlist.current_track, self.track1)
|
|
|
|
self.db_plist.add_track(self.track2)
|
|
self.playlist.request_track(self.track2)
|
|
self.assertFalse(self.playlist.can_go_next)
|
|
|
|
self.playlist.request_track(self.track1)
|
|
self.assertSetEqual(self.playlist._Playlist__picked.trackids,
|
|
{self.track1.trackid})
|
|
self.assertTrue(self.playlist.can_go_next)
|
|
|
|
def test_current_track(self):
|
|
"""Test the Playlist current-track property."""
|
|
self.assertIsNone(self.playlist.current_track)
|
|
self.playlist.current_track = self.track2
|
|
self.assertIsNone(self.playlist.current_track)
|
|
self.assertSetEqual(self.playlist._Playlist__picked.trackids, set())
|
|
|
|
self.db_plist.add_track(self.track1)
|
|
self.db_plist.add_track(self.track2)
|
|
self.db_plist.add_track(self.track3)
|
|
self.db_plist.current_trackid = self.track2.trackid
|
|
|
|
notify = unittest.mock.Mock()
|
|
self.playlist.connect("notify::current-track", notify)
|
|
self.playlist.playlist = self.db_plist
|
|
self.assertEqual(self.playlist.current_track, self.track2)
|
|
self.assertSetEqual(self.playlist._Playlist__picked.trackids,
|
|
{self.track2.trackid})
|
|
notify.assert_called()
|
|
|
|
self.db_plist.current_trackid = self.track3.trackid
|
|
self.playlist.playlist = self.db_plist
|
|
self.assertEqual(self.db_plist.current_trackid, 0)
|
|
self.assertIsNone(self.playlist.current_track)
|
|
self.assertSetEqual(self.playlist._Playlist__picked.trackids, set())
|
|
|
|
self.playlist.current_track = self.track1
|
|
self.assertEqual(self.db_plist.current_trackid, self.track1.trackid)
|
|
self.assertEqual(self.playlist.current_track, self.track1)
|
|
self.assertSetEqual(self.playlist._Playlist__picked.trackids,
|
|
{self.track1.trackid})
|
|
|
|
self.playlist.current_track = None
|
|
self.assertEqual(self.db_plist.current_trackid, 0)
|
|
self.assertIsNone(self.playlist.current_track)
|
|
self.assertSetEqual(self.playlist._Playlist__picked.trackids,
|
|
{self.track1.trackid})
|
|
|
|
self.db_plist.remove_track(self.track2)
|
|
self.db_plist.current_trackid = self.track2.trackid
|
|
|
|
notify.reset_mock()
|
|
self.db_plist.tracks.emit("trackids-reset")
|
|
self.assertEqual(self.db_plist.current_trackid, 0)
|
|
self.assertIsNone(self.playlist.current_track)
|
|
notify.assert_called()
|
|
|
|
def test_loop(self):
|
|
"""Test the Playlist loop property."""
|
|
self.assertEqual(self.playlist.loop, "None")
|
|
|
|
notify = unittest.mock.Mock()
|
|
self.playlist.connect("notify::loop", notify)
|
|
self.playlist.loop = "Track"
|
|
self.assertEqual(self.playlist.loop, "None")
|
|
notify.assert_not_called()
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
notify.assert_called()
|
|
|
|
notify.reset_mock()
|
|
self.playlist.loop = "Track"
|
|
self.assertEqual(self.db_plist.loop, "Track")
|
|
self.assertEqual(self.playlist.loop, "Track")
|
|
notify.assert_called()
|
|
|
|
notify.reset_mock()
|
|
self.db_plist.loop = "Playlist"
|
|
self.assertEqual(self.playlist.loop, "Playlist")
|
|
notify.assert_called()
|
|
|
|
self.playlist.playlist = None
|
|
notify.reset_mock()
|
|
self.db_plist.loop = "Track"
|
|
notify.assert_not_called()
|
|
|
|
def test_playlist(self):
|
|
"""Test the playlist property."""
|
|
self.assertIsNone(self.playlist.playlist)
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
self.assertEqual(self.playlist._Playlist__playlist, self.db_plist)
|
|
self.assertEqual(self.playlist.playlist, self.db_plist)
|
|
self.assertEqual(self.playlist.trackid_set, self.db_plist.tracks)
|
|
self.assertEqual(self.playlist.sort_order, self.db_plist.sort_order)
|
|
|
|
self.playlist.playlist = None
|
|
self.assertIsNone(self.playlist.playlist)
|
|
self.assertIsNone(self.playlist.trackid_set)
|
|
|
|
def test_shuffle(self):
|
|
"""Test the Playlist shuffle property."""
|
|
self.assertFalse(self.playlist.shuffle)
|
|
|
|
notify = unittest.mock.Mock()
|
|
self.playlist.connect("notify::shuffle", notify)
|
|
self.playlist.shuffle = True
|
|
self.assertFalse(self.playlist.shuffle)
|
|
notify.assert_not_called()
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
notify.assert_called()
|
|
|
|
notify.reset_mock()
|
|
self.playlist.shuffle = True
|
|
self.assertTrue(self.playlist.shuffle)
|
|
self.assertTrue(self.db_plist.shuffle)
|
|
notify.assert_called()
|
|
|
|
notify.reset_mock()
|
|
self.db_plist.shuffle = False
|
|
self.assertFalse(self.playlist.shuffle)
|
|
notify.assert_called()
|
|
|
|
self.playlist.playlist = None
|
|
notify.reset_mock()
|
|
self.db_plist.shuffle = True
|
|
notify.assert_not_called()
|
|
|
|
def test_sort_order(self):
|
|
"""Test the sort-order property."""
|
|
notify = unittest.mock.Mock()
|
|
self.playlist.connect("notify::sort-order", notify)
|
|
|
|
self.assertIsNone(self.playlist.sort_order)
|
|
self.db_plist.add_track(self.track1)
|
|
self.db_plist.add_track(self.track2)
|
|
self.db_plist.add_track(self.track3)
|
|
|
|
self.playlist.playlist = self.db_plist
|
|
self.assertEqual(self.playlist.sort_order, self.db_plist.sort_order)
|
|
notify.assert_called()
|
|
|
|
self.playlist.sort_order = "length DESC"
|
|
self.assertEqual(self.db_plist.sort_order, "length DESC")
|
|
self.assertDictEqual(self.playlist._Playlist__sort_keys,
|
|
{self.track3.trackid: 0,
|
|
self.track2.trackid: 1,
|
|
self.track1.trackid: 2})
|
|
self.assertListEqual(self.playlist.trackids,
|
|
[self.track3.trackid,
|
|
self.track2.trackid,
|
|
self.track1.trackid])
|
|
|
|
self.db_plist.remove_track(self.track2)
|
|
self.assertDictEqual(self.playlist._Playlist__sort_keys,
|
|
{self.track3.trackid: 0,
|
|
self.track1.trackid: 2})
|
|
|
|
notify.reset_mock()
|
|
self.db_plist.sort_order = "user"
|
|
self.assertEqual(self.playlist.sort_order, "user")
|
|
notify.assert_called()
|
|
|
|
notify.reset_mock()
|
|
self.playlist.playlist = None
|
|
notify.assert_called()
|
|
|
|
notify.reset_mock()
|
|
self.db_plist.sort_order = "length"
|
|
self.assertIsNone(self.playlist.sort_order)
|
|
notify.assert_not_called()
|
|
|
|
self.playlist.sort_order = "length"
|
|
self.assertIsNone(self.playlist.sort_order)
|
|
notify.assert_not_called()
|
|
|
|
|
|
class TestPlaylistNextTrack(tests.util.TestCase):
|
|
"""Test the Playlist next_track() function."""
|
|
|
|
def setUpTrack(self, i: int) -> emmental.db.tracks.Track:
|
|
"""Create a Track, add it to the Playlist, and return it."""
|
|
track = self.sql.tracks.create(self.library,
|
|
pathlib.Path(f"/a/b/{i}.ogg"),
|
|
self.medium, self.year, number=i)
|
|
self.db_plist.add_track(track)
|
|
return track
|
|
|
|
def setUp(self):
|
|
"""Set up common variables."""
|
|
super().setUp()
|
|
self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
|
|
self.album = self.sql.albums.create("Test Album", "Artist", "2023")
|
|
self.medium = self.sql.media.create(self.album, "", number=1)
|
|
self.year = self.sql.years.create(2023)
|
|
|
|
self.playlist = emmental.playlist.playlist.Playlist(self.sql)
|
|
self.db_plist = self.sql.playlists.create("Test Playlist")
|
|
self.playlist.playlist = self.db_plist
|
|
|
|
self.tracks = [self.setUpTrack(i) for i in range(1, 6)]
|
|
|
|
def test_next_track(self):
|
|
"""Test the Playlist next_track() function with no extra flags."""
|
|
for i, track in enumerate(self.tracks):
|
|
with self.subTest(i=i, track=track.path):
|
|
self.assertEqual(self.playlist.next_track(), track)
|
|
self.assertEqual(self.playlist.current_track, track)
|
|
|
|
self.assertIsNone(self.playlist.next_track())
|
|
self.assertEqual(self.playlist.current_track, self.tracks[-1])
|
|
|
|
def test_loop_track(self):
|
|
"""Test the next_track() function with ::loop='Track'."""
|
|
self.playlist.loop = "Track"
|
|
|
|
for i in range(3):
|
|
with self.subTest(i=i):
|
|
self.assertEqual(self.playlist.next_track(), self.tracks[0])
|
|
self.assertEqual(self.playlist.current_track, self.tracks[0])
|
|
|
|
def test_loop_playlist(self):
|
|
"""Test the next_track() function with ::loop='Playlist'."""
|
|
self.playlist.loop = "Playlist"
|
|
|
|
for i, track in enumerate(self.tracks):
|
|
with self.subTest(i=i, track=track.path):
|
|
self.assertEqual(self.playlist.next_track(), track)
|
|
self.assertEqual(self.playlist.current_track, track)
|
|
|
|
for i, track in enumerate(self.tracks):
|
|
with self.subTest(i=i, track=track.path):
|
|
self.assertEqual(self.playlist.next_track(), track)
|
|
self.assertEqual(self.playlist.current_track, track)
|
|
|
|
@unittest.mock.patch("random.choice")
|
|
def test_shuffle(self, mock_random: unittest.mock.Mock()):
|
|
"""Test the next_track() function with ::shuffle=True."""
|
|
self.playlist.shuffle = True
|
|
|
|
mock_random.return_value = 3
|
|
self.assertEqual(self.playlist.next_track(), self.tracks[2])
|
|
mock_random.assert_called_with([1, 2, 3, 4, 5])
|
|
|
|
mock_random.return_value = 5
|
|
self.assertEqual(self.playlist.next_track(), self.tracks[4])
|
|
mock_random.assert_called_with([1, 2, 4, 5])
|
|
|
|
self.db_plist.tracks.trackids = set()
|
|
self.assertIsNone(self.playlist.next_track())
|
|
|
|
@unittest.mock.patch("random.choice")
|
|
def test_shuffle_loop_track(self, mock_random: unittest.mock.Mock()):
|
|
"""Test next_track() with ::shuffle=True and ::loop='Track'."""
|
|
self.playlist.loop = "Track"
|
|
self.playlist.shuffle = True
|
|
|
|
mock_random.return_value = 3
|
|
self.assertEqual(self.playlist.next_track(), self.tracks[2])
|
|
mock_random.assert_called_with([1, 2, 3, 4, 5])
|
|
|
|
mock_random.reset_mock()
|
|
self.assertEqual(self.playlist.next_track(), self.tracks[2])
|
|
mock_random.assert_not_called()
|
|
|
|
@unittest.mock.patch("random.choice")
|
|
def test_shuffle_loop_playlist(self, mock_random: unittest.mock.Mock()):
|
|
"""Test next_track() with ::shuffle=True and ::loop='Playlist'."""
|
|
self.playlist.loop = "Playlist"
|
|
self.playlist.shuffle = True
|
|
|
|
for i in range(5):
|
|
with self.subTest(i=i):
|
|
mock_random.return_value = i + 1
|
|
self.assertEqual(self.playlist.next_track(), self.tracks[i])
|
|
|
|
for i in range(5):
|
|
with self.subTest(i=i):
|
|
mock_random.return_value = i + 1
|
|
self.assertEqual(self.playlist.next_track(), self.tracks[i])
|