emmental/tests/db/test_playlist.py

354 lines
15 KiB
Python

# Copyright 2022 (c) Anna Schumaker
"""Tests our ListStore and Playlist objects."""
import pathlib
import unittest
import unittest.mock
import emmental.db.playlist
import tests.util.playlist
from gi.repository import Gio
from gi.repository import Gtk
class TestPlaylistRow(unittest.TestCase):
"""Tests our shared Playlist Row."""
def setUp(self):
"""Set up common variables."""
self.table = Gio.ListStore()
self.table.add_track = unittest.mock.Mock(return_value=True)
self.table.remove_track = unittest.mock.Mock(return_value=True)
self.table.move_track_down = unittest.mock.Mock(return_value=True)
self.table.move_track_up = unittest.mock.Mock(return_value=True)
self.table.get_trackids = unittest.mock.Mock(return_value={1, 2, 3})
self.table.queue = emmental.db.idle.Queue()
self.table.update = unittest.mock.Mock(return_value=True)
self.playlist = emmental.db.playlist.Playlist(table=self.table,
propertyid=0,
name="Test Playlist")
self.track = emmental.db.tracks.Track(table=None, trackid=12345)
def test_init(self):
"""Test that the Playlist object is configured correctly."""
self.assertIsInstance(self.playlist, emmental.db.table.Row)
self.assertIsInstance(self.playlist.tracks,
emmental.db.tracks.TrackidSet)
self.assertEqual(self.playlist.table, self.table)
self.assertEqual(self.playlist.propertyid, 0)
self.assertEqual(self.playlist.name, "Test Playlist")
self.assertFalse(self.playlist.active)
self.assertEqual(self.playlist.n_tracks, 0)
self.assertFalse(self.playlist.tracks_loaded)
playlist2 = emmental.db.playlist.Playlist(table=self.table,
propertyid=1,
name="Test Name", active=1)
self.assertEqual(playlist2.propertyid, 1)
self.assertEqual(playlist2.name, "Test Name")
self.assertTrue(playlist2.active)
def test_children(self):
"""Test the child playlist properties."""
self.assertIsNone(self.playlist.children)
filter = Gtk.Filter()
self.playlist.add_children(self.table, filter)
self.assertIsInstance(self.playlist.children, Gtk.FilterListModel)
self.assertEqual(self.playlist.children.get_filter(), filter)
self.assertEqual(self.playlist.children.get_model(), self.table)
self.assertTrue(self.playlist.children.get_incremental())
def test_parent(self):
"""Test the parent playlist property."""
self.assertIsNone(self.playlist.parent)
def test_do_update(self):
"""Test the do_update() function."""
for (prop, value) in [("name", "New Name"), ("propertyid", 12345),
("children", Gtk.FilterListModel()),
("n-tracks", 42), ("tracks-loaded", True),
("tracks-movable", True)]:
with self.subTest(property=prop):
self.playlist.set_property(prop, value)
self.table.update.assert_not_called()
self.playlist.active = True
self.table.update.assert_called_with(self.playlist, "active", True)
def test_add_track(self):
"""Test adding a track to the playlist."""
self.playlist.add_track(self.track, idle=True)
self.table.add_track.assert_called_with(self.playlist, self.track)
self.assertNotIn(self.track, self.playlist.tracks)
self.assertEqual(self.table.queue[0],
(self.playlist._Playlist__add_track, self.track))
self.playlist.add_track(self.track)
self.table.add_track.assert_called_with(self.playlist, self.track)
self.assertIn(self.track, self.playlist.tracks)
self.assertEqual(self.playlist.n_tracks, 1)
self.playlist.tracks.trackids.clear()
self.table.add_track.return_value = False
self.playlist.add_track(self.track)
self.assertNotIn(self.track, self.playlist.tracks)
def test_has_track(self):
"""Test the playlist has_track() function."""
self.assertFalse(self.playlist.has_track(self.track))
self.playlist.add_track(self.track)
self.assertTrue(self.playlist.has_track(self.track))
self.playlist.remove_track(self.track)
self.assertFalse(self.playlist.has_track(self.track))
def test_move_tracks(self):
"""Test the move_track_up() and move_track_down() functions."""
self.assertFalse(self.playlist.tracks_movable)
self.assertTrue(self.playlist.move_track_down(self.track))
self.table.move_track_down.assert_called_with(self.playlist,
self.track)
self.assertTrue(self.playlist.move_track_up(self.track))
self.table.move_track_up.assert_called_with(self.playlist, self.track)
def test_remove_track(self):
"""Test removing a track from the playlist."""
self.playlist.tracks.trackids.add(self.track.trackid)
self.playlist.remove_track(self.track, idle=True)
self.table.remove_track.assert_not_called()
self.assertIn(self.track, self.playlist.tracks)
self.assertEqual(self.table.queue[0],
(self.playlist._Playlist__remove_track, self.track))
self.playlist.remove_track(self.track)
self.table.remove_track.assert_called_with(self.playlist, self.track)
self.assertNotIn(self.track, self.playlist.tracks)
self.assertEqual(self.playlist.n_tracks, 0)
self.playlist.tracks.trackids.add(self.track.trackid)
self.table.remove_track.return_value = False
self.playlist.remove_track(self.track)
self.table.remove_track.assert_called_with(self.playlist, self.track)
self.assertNotIn(self.track, self.playlist.tracks)
def test_load_tracks(self):
"""Test loading a Playlist's Tracks."""
self.assertEqual(self.playlist.n_tracks, 0)
self.assertFalse(self.playlist.tracks_loaded)
self.assertTrue(self.playlist.load_tracks())
self.table.get_trackids.assert_called_with(self.playlist)
self.assertSetEqual(self.playlist.tracks.trackids, {1, 2, 3})
self.assertTrue(self.playlist.tracks_loaded)
self.table.get_trackids.reset_mock()
self.assertTrue(self.playlist.load_tracks())
self.table.get_trackids.assert_not_called()
def test_reload_tracks(self):
"""Test reloading a Playlist's Tracks."""
self.playlist.tracks_loaded = True
self.playlist.reload_tracks(idle=True)
self.table.get_trackids.assert_not_called()
self.assertEqual(self.table.queue[0], (self.playlist.load_tracks,))
self.playlist.tracks_loaded = True
self.playlist.reload_tracks()
self.table.get_trackids.assert_called_with(self.playlist)
self.assertSetEqual(self.playlist.tracks.trackids, {1, 2, 3})
class TestPlaylistTable(tests.util.TestCase):
"""Tests our Playlist Table."""
def setUp(self):
"""Set up common variables."""
super().setUp()
self.table = tests.util.playlist.MockTable(self.sql)
self.sql("DELETE FROM playlist_properties")
self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
self.album = self.sql.albums.create("Test Album", "Artist", "2023-03")
self.medium = self.sql.media.create(self.album, "", number=1)
self.year = self.sql.years.create(2023)
self.track = self.sql.tracks.create(self.library,
pathlib.Path("/a/b/c.ogg"),
self.medium, self.year)
def test_treemodel(self):
"""Check that the table's treemodel was set up properly."""
self.assertIsInstance(self.table.treemodel, Gtk.TreeListModel)
self.assertEqual(self.table.treemodel.get_model(), self.table)
self.assertFalse(self.table.treemodel.get_passthrough())
self.assertFalse(self.table.treemodel.get_autoexpand())
root = self.table.create("Root")
self.assertIsNone(self.table._Table__create_tree(root))
root.children = Gtk.FilterListModel()
self.assertEqual(self.table._Table__create_tree(root), root.children)
def test_add_track(self):
"""Test adding a track to a playlist."""
self.assertTrue(self.table.system_tracks)
plist = self.table.create("Test Playlist")
self.library.deleting = True
self.assertFalse(self.table.add_track(plist, None))
self.assertFalse(self.table.add_track(plist, self.track))
self.library.deleting = False
self.assertTrue(self.table.add_track(plist, self.track))
cur = self.sql("SELECT COUNT(*) FROM system_tracks")
self.assertEqual(cur.fetchone()["COUNT(*)"], 1)
self.assertFalse(self.table.add_track(plist, self.track))
self.table.system_tracks = False
with self.assertRaises(NotImplementedError):
self.table.add_track(plist, self.track)
def test_construct(self):
"""Test constructing a new playlist."""
self.assertIsNone(self.table.active_playlist)
plist1 = self.table.construct(propertyid=1, name="Test")
self.assertIsInstance(plist1, emmental.db.playlist.Playlist)
self.assertEqual(plist1.table, self.table)
self.assertEqual(plist1.propertyid, 1)
self.assertEqual(plist1.name, "Test")
self.assertFalse(plist1.active)
plist2 = self.table.construct(propertyid=2, name="Test 2", active=True)
self.assertEqual(self.table.active_playlist, plist2)
self.assertEqual(self.sql.active_playlist, plist2)
self.assertTrue(plist2.active)
self.assertEqual(self.table.queue[0], (plist1.load_tracks,))
self.assertEqual(self.table.queue[1], (plist2.load_tracks,))
def test_get_sort_key(self):
"""Test getting a sort key for a playlist."""
plist = self.table.create("Playlist 1")
self.assertTupleEqual(self.table.get_sort_key(plist),
("playlist", "1"))
def test_clear(self):
"""Test clearing the active_playlist property."""
plist = self.table.create("Playlist 1")
self.table.active_playlist = plist
self.table.clear()
self.assertIsNone(self.table.active_playlist)
self.assertEqual(len(self.table), 0)
def test_delete(self):
"""Test deleting the active playlist with system tracks."""
self.table.system_tracks = True
plist = self.table.create("Test Playlist")
plist.add_track(self.track)
self.sql.set_active_playlist(plist)
self.assertTrue(self.table.delete(plist))
self.assertIsNone(self.table.active_playlist)
self.assertIsNone(self.sql.active_playlist)
self.assertNotIn(plist, self.table)
cur = self.sql("SELECT COUNT(*) FROM system_tracks")
self.assertEqual(cur.fetchone()["COUNT(*)"], 0)
def test_get_trackids(self):
"""Test getting the set of trackids for this playlist."""
self.assertTrue(self.table.system_tracks)
self.table._Table__autodelete = unittest.mock.Mock()
plist = self.table.create("Test Playlist")
self.assertSetEqual(self.table.get_trackids(plist), set())
self.table._Table__autodelete.assert_called_with(plist)
plist.add_track(self.track)
self.assertSetEqual(self.table.get_trackids(plist),
{self.track.trackid})
self.library.deleting = True
self.assertSetEqual(self.table.get_trackids(plist), set())
self.table.system_tracks = False
with self.assertRaises(NotImplementedError):
self.table.get_trackids(plist)
def test_move_track_down(self):
"""Test moving tracks down in the sort order."""
plist = self.table.create("Test Playlist")
self.assertFalse(self.table.move_track_down(plist, self.track))
plist.tracks_movable = True
with self.assertRaises(NotImplementedError):
self.table.move_track_down(plist, self.track)
def test_move_track_up(self):
"""Test moving tracks up in the sort order."""
plist = self.table.create("Test Playlist")
self.assertFalse(self.table.move_track_up(plist, self.track))
plist.tracks_movable = True
with self.assertRaises(NotImplementedError):
self.table.move_track_up(plist, self.track)
def test_remove_track(self):
"""Test adding a track to a playlist."""
self.assertTrue(self.table.system_tracks)
self.table._Table__autodelete = unittest.mock.Mock()
plist = self.table.create("Test Playlist")
plist.add_track(self.track)
self.assertTrue(self.table.remove_track(plist, self.track))
cur = self.sql("SELECT COUNT(*) FROM system_tracks")
self.assertEqual(cur.fetchone()["COUNT(*)"], 0)
self.assertFalse(self.table.remove_track(plist, self.track))
self.table._Table__autodelete.assert_called_with(plist)
self.table.system_tracks = False
with self.assertRaises(NotImplementedError):
self.table.remove_track(plist, self.track)
def test_update(self):
"""Test updating playlist properties."""
plist1 = self.table.create("Test Playlist 1")
plist2 = self.table.create("Test Playlist 2")
plist1.active = True
self.assertEqual(self.table.active_playlist, plist1)
row = self.sql("""SELECT active FROM playlist_properties
WHERE propertyid=?""", plist1.propertyid).fetchone()
self.assertEqual(row["active"], True)
plist2.active = True
self.assertEqual(self.table.active_playlist, plist2)
row = self.sql("SELECT active FROM playlist_properties WHERE rowid=?",
plist1.propertyid).fetchone()
self.assertEqual(row["active"], False)
def test_autodelete(self):
"""Test automatically deleting playlists."""
plist = self.table.create("Test Playlist")
self.table.queue.cancel()
self.assertFalse(self.table.autodelete)
self.table._Table__autodelete(plist)
self.assertFalse(self.table.queue.running)
self.assertIn(plist, self.table)
self.table.autodelete = True
self.table._Table__autodelete(plist)
self.assertTupleEqual(self.table.queue[0],
(self.table._Table__do_autodelete, plist))
plist.n_tracks = 1
self.assertTrue(self.table._Table__do_autodelete(plist))
self.assertIn(plist, self.table)
plist.n_tracks = 0
self.assertTrue(self.table._Table__do_autodelete(plist))
self.assertNotIn(plist, self.table)