Anna Schumaker
c5f9608c49
Otherwise we could lose the changes if the app crashes. Fixes: #63 ("The database isn't being committed enough") Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
466 lines
19 KiB
Python
466 lines
19 KiB
Python
# Copyright 2023 (c) Anna Schumaker.
|
|
"""Tests our Tracklist Selection OSD."""
|
|
import pathlib
|
|
import unittest
|
|
import emmental.buttons
|
|
import emmental.tracklist.selection
|
|
import tests.util
|
|
import unittest.mock
|
|
from gi.repository import Gtk
|
|
from gi.repository import Adw
|
|
|
|
|
|
class TestPlaylistRowWidget(unittest.TestCase):
|
|
"""Test the Playlist Row Widget."""
|
|
|
|
def setUp(self):
|
|
"""Set up common variables."""
|
|
self.widget = emmental.tracklist.selection.PlaylistRowWidget()
|
|
|
|
def test_init(self):
|
|
"""Test that the Playlist Row Widget is set up properly."""
|
|
self.assertIsInstance(self.widget, Gtk.Box)
|
|
|
|
def test_label(self):
|
|
"""Test the Playlist Row Widget label."""
|
|
self.widget.name = "Test Playlist Name"
|
|
self.assertIsInstance(self.widget._label, Gtk.Label)
|
|
self.assertEqual(self.widget._label.get_text(), "Test Playlist Name")
|
|
self.assertEqual(self.widget._label.get_xalign(), 0.0)
|
|
self.assertEqual(self.widget._icon.get_next_sibling(),
|
|
self.widget._label)
|
|
|
|
def test_icon(self):
|
|
"""Test the Playlist Row Widget icon."""
|
|
self.assertIsInstance(self.widget._icon, Adw.Avatar)
|
|
self.assertEqual(self.widget.get_first_child(), self.widget._icon)
|
|
self.assertEqual(self.widget._icon.get_size(), 32)
|
|
|
|
self.widget.name = "Favorite Tracks"
|
|
self.assertEqual(self.widget._icon.get_icon_name(),
|
|
"heart-filled-symbolic")
|
|
self.assertEqual(self.widget._icon.get_text(), "Favorite Tracks")
|
|
|
|
self.widget.name = "Queued Tracks"
|
|
self.assertEqual(self.widget._icon.get_icon_name(),
|
|
"music-queue-symbolic")
|
|
self.assertEqual(self.widget._icon.get_text(), "Queued Tracks")
|
|
|
|
self.widget.name = "Any Other Name"
|
|
self.assertEqual(self.widget._icon.get_icon_name(),
|
|
"playlist2-symbolic")
|
|
self.assertEqual(self.widget._icon.get_text(), "Any Other Name")
|
|
|
|
def test_image(self):
|
|
"""Test the Playlist Row Widget image."""
|
|
self.assertIsNone(self.widget.image)
|
|
self.widget.image = tests.util.COVER_JPG
|
|
self.assertIsNotNone(self.widget._icon.get_custom_image())
|
|
self.widget.image = None
|
|
self.assertIsNone(self.widget._icon.get_custom_image())
|
|
self.widget.image = pathlib.Path("/a/b/c.jpg")
|
|
self.assertIsNone(self.widget._icon.get_custom_image())
|
|
|
|
|
|
class TestPlaylistRow(tests.util.TestCase):
|
|
"""Test the PlaylistRow widget."""
|
|
|
|
def setUp(self):
|
|
"""Set up common variables."""
|
|
super().setUp()
|
|
self.playlist = self.sql.playlists.create("Test Playlist")
|
|
self.listitem = Gtk.ListItem()
|
|
self.listitem.get_item = unittest.mock.Mock(return_value=self.playlist)
|
|
self.row = emmental.tracklist.selection.PlaylistRow(self.listitem)
|
|
|
|
def test_init(self):
|
|
"""Test that the PlaylistRow is initialized properly."""
|
|
self.assertIsInstance(self.row, emmental.factory.ListRow)
|
|
self.assertIsInstance(self.row.child,
|
|
emmental.tracklist.selection.PlaylistRowWidget)
|
|
|
|
def test_bind(self):
|
|
"""Test binding the PlaylistRow."""
|
|
self.row.bind()
|
|
self.assertEqual(self.row.child.name, "Test Playlist")
|
|
self.assertIsNone(self.row.child.image)
|
|
|
|
self.playlist.image = pathlib.Path("/a/b/c.jpg")
|
|
self.assertEqual(self.row.child.image, pathlib.Path("/a/b/c.jpg"))
|
|
|
|
|
|
class TestUserTracksFilter(tests.util.TestCase):
|
|
"""Test the UserTracksFilter."""
|
|
|
|
def setUp(self):
|
|
"""Set up common variables."""
|
|
super().setUp()
|
|
self.sql.playlists.load(now=True)
|
|
self.filter = emmental.tracklist.selection.UserTracksFilter()
|
|
self.db_plist = self.sql.playlists.create("Test Playlist")
|
|
|
|
def test_init(self):
|
|
"""Test that the filter is initialized properly."""
|
|
self.assertIsInstance(self.filter, Gtk.Filter)
|
|
self.assertIsNone(self.filter.playlist)
|
|
|
|
def test_changed(self):
|
|
"""Test the filter changed property."""
|
|
changed = unittest.mock.Mock()
|
|
self.filter.connect("changed", changed)
|
|
self.filter.playlist = self.db_plist
|
|
changed.assert_called_with(self.filter, Gtk.FilterChange.DIFFERENT)
|
|
|
|
def test_match(self):
|
|
"""Test the filter match function."""
|
|
self.assertTrue(self.filter.match(self.db_plist))
|
|
|
|
self.db_plist.user_tracks = False
|
|
self.assertFalse(self.filter.match(self.db_plist))
|
|
|
|
self.filter.playlist = self.db_plist
|
|
self.db_plist.user_tracks = True
|
|
self.assertFalse(self.filter.match(self.db_plist))
|
|
|
|
|
|
class TestPlaylistView(tests.util.TestCase):
|
|
"""Test the PlaylistView widget."""
|
|
|
|
def setUp(self):
|
|
"""Set up common variables."""
|
|
super().setUp()
|
|
self.sql.playlists.load(now=True)
|
|
self.view = emmental.tracklist.selection.PlaylistView(self.sql)
|
|
|
|
def test_init(self):
|
|
"""Test that the Playlist View is set up properly."""
|
|
self.assertIsInstance(self.view, Gtk.ListView)
|
|
|
|
self.assertTrue(self.view.get_show_separators())
|
|
self.assertTrue(self.view.get_single_click_activate())
|
|
self.assertTrue(self.view.has_css_class("rich-list"))
|
|
|
|
def test_models(self):
|
|
"""Test that the models have been connected correctly."""
|
|
self.assertIsInstance(self.view._selection, Gtk.NoSelection)
|
|
self.assertIsInstance(self.view._filtered, Gtk.FilterListModel)
|
|
self.assertIsInstance(self.view._filtered.get_filter(),
|
|
emmental.tracklist.selection.UserTracksFilter)
|
|
|
|
self.assertEqual(self.view.get_model(), self.view._selection)
|
|
self.assertEqual(self.view._selection.get_model(), self.view._filtered)
|
|
self.assertEqual(self.view._filtered.get_model(), self.sql.playlists)
|
|
|
|
def test_factory(self):
|
|
"""Test that the factory has been configured correctly."""
|
|
self.assertIsInstance(self.view._factory, emmental.factory.Factory)
|
|
self.assertEqual(self.view.get_factory(), self.view._factory)
|
|
self.assertEqual(self.view._factory.row_type,
|
|
emmental.tracklist.selection.PlaylistRow)
|
|
|
|
def test_activate(self):
|
|
"""Test activating a Playlist Row for adding tracks."""
|
|
selected = unittest.mock.Mock()
|
|
self.view.connect("playlist-selected", selected)
|
|
self.view.emit("activate", 0)
|
|
selected.assert_called_with(self.view, self.sql.playlists.favorites)
|
|
|
|
|
|
class TestMoveButtons(unittest.TestCase):
|
|
"""Test the Tracklist move up & down buttons."""
|
|
|
|
def setUp(self):
|
|
"""Set up common variables."""
|
|
self.move = emmental.tracklist.selection.MoveButtons()
|
|
|
|
def test_init(self):
|
|
"""Test that the move buttons were set up properly."""
|
|
self.assertIsInstance(self.move, Gtk.Box)
|
|
self.assertTrue(self.move.has_css_class("emmental-move-buttons"))
|
|
self.assertTrue(self.move.has_css_class("large-icons"))
|
|
self.assertTrue(self.move.has_css_class("linked"))
|
|
|
|
def test_move_down(self):
|
|
"""Test the move down button."""
|
|
self.assertIsInstance(self.move._down, Gtk.Button)
|
|
self.assertEqual(self.move._down.get_icon_name(), "go-down-symbolic")
|
|
self.assertTrue(self.move._down.has_css_class("opaque"))
|
|
self.assertTrue(self.move._down.has_css_class("pill"))
|
|
self.assertTrue(self.move._down.get_hexpand())
|
|
|
|
move_down = unittest.mock.Mock()
|
|
self.move.connect("move-down", move_down)
|
|
self.move._down.emit("clicked")
|
|
move_down.assert_called()
|
|
|
|
self.assertEqual(self.move._up.get_next_sibling(), self.move._down)
|
|
|
|
def test_can_move_down(self):
|
|
"""Test the can-move-down property."""
|
|
self.assertFalse(self.move.can_move_down)
|
|
self.assertFalse(self.move._down.get_sensitive())
|
|
|
|
self.move.can_move_down = True
|
|
self.assertTrue(self.move._down.get_sensitive())
|
|
self.move.can_move_down = False
|
|
self.assertFalse(self.move._down.get_sensitive())
|
|
|
|
def test_move_up(self):
|
|
"""Test the move up button."""
|
|
self.assertIsInstance(self.move._up, Gtk.Button)
|
|
self.assertEqual(self.move._up.get_icon_name(), "go-up-symbolic")
|
|
self.assertTrue(self.move._up.has_css_class("opaque"))
|
|
self.assertTrue(self.move._up.has_css_class("pill"))
|
|
self.assertTrue(self.move._up.get_hexpand())
|
|
|
|
move_up = unittest.mock.Mock()
|
|
self.move.connect("move-up", move_up)
|
|
self.move._up.emit("clicked")
|
|
move_up.assert_called()
|
|
|
|
self.assertEqual(self.move.get_first_child(), self.move._up)
|
|
|
|
def test_can_move_up(self):
|
|
"""Test the can-move-up property."""
|
|
self.assertFalse(self.move.can_move_up)
|
|
self.assertFalse(self.move._up.get_sensitive())
|
|
|
|
self.move.can_move_up = True
|
|
self.assertTrue(self.move._up.get_sensitive())
|
|
self.move.can_move_up = False
|
|
self.assertFalse(self.move._up.get_sensitive())
|
|
|
|
|
|
class TestOsd(tests.util.TestCase):
|
|
"""Test the Tracklist OSD."""
|
|
|
|
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.db_plist)
|
|
self.model = Gtk.StringList.new(["Test", "OSD", "Strings"])
|
|
self.selection = Gtk.MultiSelection(model=self.model)
|
|
self.osd = emmental.tracklist.selection.OSD(self.sql, self.selection)
|
|
|
|
def test_init(self):
|
|
"""Test that the OSD is set up properly."""
|
|
self.assertIsInstance(self.osd, Gtk.Overlay)
|
|
self.assertIsInstance(self.osd._sizegroup, Gtk.SizeGroup)
|
|
self.assertEqual(self.osd.selection, self.selection)
|
|
self.assertEqual(self.osd.sql, self.sql)
|
|
self.assertIsNone(self.osd.playlist)
|
|
|
|
self.assertEqual(self.osd._sizegroup.get_mode(),
|
|
Gtk.SizeGroupMode.HORIZONTAL)
|
|
|
|
def test_add_button(self):
|
|
"""Test the add tracks button."""
|
|
self.assertIsInstance(self.osd._add, emmental.buttons.PopoverButton)
|
|
self.assertIsInstance(self.osd._add.get_child(), Adw.ButtonContent)
|
|
self.assertIsInstance(self.osd._add.popover_child,
|
|
emmental.tracklist.selection.PlaylistView)
|
|
self.assertEqual(self.osd._add.get_child().get_icon_name(),
|
|
"list-add-symbolic")
|
|
self.assertEqual(self.osd._add.get_child().get_label(), "Add")
|
|
self.assertEqual(self.osd._add.get_halign(), Gtk.Align.START)
|
|
self.assertEqual(self.osd._add.get_valign(), Gtk.Align.END)
|
|
self.assertEqual(self.osd._add.get_margin_start(), 16)
|
|
self.assertEqual(self.osd._add.get_margin_bottom(), 16)
|
|
self.assertEqual(self.osd._add.get_direction(), Gtk.ArrowType.UP)
|
|
self.assertFalse(self.osd._add.get_visible())
|
|
|
|
self.assertTrue(self.osd._add.has_css_class("suggested-action"))
|
|
self.assertTrue(self.osd._add.has_css_class("pill"))
|
|
|
|
self.assertIn(self.osd._add, self.osd)
|
|
self.assertIn(self.osd._add, self.osd._sizegroup.get_widgets())
|
|
|
|
self.osd.playlist = self.playlist
|
|
self.osd.reset()
|
|
self.assertEqual(self.osd._add.popover_child.playlist, self.db_plist)
|
|
|
|
def test_add_button_visible(self):
|
|
"""Test the add button visiblity."""
|
|
self.assertFalse(self.osd._add.get_visible())
|
|
|
|
self.selection.select_item(0, True)
|
|
self.assertFalse(self.osd._add.get_visible())
|
|
|
|
self.osd.playlist = self.playlist
|
|
self.selection.select_item(1, True)
|
|
self.assertTrue(self.osd._remove.get_visible())
|
|
|
|
def test_add_button_activate(self):
|
|
"""Test activating a playlist in the add button."""
|
|
with unittest.mock.patch.object(self.db_plist,
|
|
"add_track") as mock_add:
|
|
self.selection.select_all()
|
|
with unittest.mock.patch.object(self.sql, "commit") as mock_commit:
|
|
self.osd._add.popover_child.emit("playlist-selected",
|
|
self.db_plist)
|
|
mock_add.assert_has_calls([unittest.mock.call(self.model[0]),
|
|
unittest.mock.call(self.model[1]),
|
|
unittest.mock.call(self.model[2])])
|
|
mock_commit.assert_called_once()
|
|
self.assertEqual(self.osd.n_selected, 0)
|
|
|
|
def test_remove_button(self):
|
|
"""Test the remove tracks button."""
|
|
self.assertIsInstance(self.osd._remove, Gtk.Button)
|
|
self.assertIsInstance(self.osd._remove.get_child(), Adw.ButtonContent)
|
|
self.assertEqual(self.osd._remove.get_child().get_icon_name(),
|
|
"list-remove-symbolic")
|
|
self.assertEqual(self.osd._remove.get_child().get_label(), "Remove")
|
|
self.assertEqual(self.osd._remove.get_halign(), Gtk.Align.END)
|
|
self.assertEqual(self.osd._remove.get_valign(), Gtk.Align.END)
|
|
self.assertEqual(self.osd._remove.get_margin_end(), 16)
|
|
self.assertEqual(self.osd._remove.get_margin_bottom(), 16)
|
|
|
|
self.assertTrue(self.osd._remove.has_css_class("destructive-action"))
|
|
self.assertTrue(self.osd._remove.has_css_class("pill"))
|
|
|
|
self.assertIn(self.osd._remove, self.osd)
|
|
self.assertIn(self.osd._remove, self.osd._sizegroup.get_widgets())
|
|
|
|
def test_remove_button_visible(self):
|
|
"""Test the remove button visiblity."""
|
|
self.assertFalse(self.osd._remove.get_visible())
|
|
|
|
self.selection.select_item(0, True)
|
|
self.assertFalse(self.osd._remove.get_visible())
|
|
|
|
self.db_plist.user_tracks = False
|
|
self.osd.playlist = self.playlist
|
|
self.selection.select_item(1, True)
|
|
self.assertFalse(self.osd._remove.get_visible())
|
|
|
|
self.db_plist.user_tracks = True
|
|
self.selection.select_item(2, True)
|
|
self.assertTrue(self.osd._remove.get_visible())
|
|
|
|
def test_remove_button_click(self):
|
|
"""Test clicking the remove button."""
|
|
with unittest.mock.patch.object(self.db_plist,
|
|
"remove_track") as mock_remove:
|
|
with unittest.mock.patch.object(self.sql, "commit") as mock_commit:
|
|
self.selection.select_all()
|
|
self.osd._remove.emit("clicked")
|
|
mock_remove.assert_not_called()
|
|
mock_commit.assert_not_called()
|
|
|
|
self.osd.playlist = self.playlist
|
|
self.selection.select_all()
|
|
self.osd._remove.emit("clicked")
|
|
mock_remove.assert_has_calls([unittest.mock.call(self.model[i])
|
|
for i in range(3)])
|
|
mock_commit.assert_called_once()
|
|
|
|
def test_move_buttons(self):
|
|
"""Test the move buttons."""
|
|
self.assertIsInstance(self.osd._move,
|
|
emmental.tracklist.selection.MoveButtons)
|
|
self.assertEqual(self.osd._move.get_halign(), Gtk.Align.CENTER)
|
|
self.assertEqual(self.osd._move.get_valign(), Gtk.Align.END)
|
|
self.assertEqual(self.osd._move.get_margin_bottom(), 16)
|
|
|
|
self.assertIn(self.osd._move, self.osd._sizegroup.get_widgets())
|
|
self.assertIn(self.osd._move, self.osd)
|
|
|
|
def test_move_button_clicks(self):
|
|
"""Test clicking the move buttons."""
|
|
set_incremental = unittest.mock.Mock()
|
|
self.model.set_incremental = set_incremental
|
|
self.osd.playlist = self.playlist
|
|
self.selection.select_item(1, True)
|
|
|
|
with unittest.mock.patch.object(self.playlist,
|
|
"move_track_down") as mock_move_down:
|
|
with unittest.mock.patch.object(self.sql, "commit") as mock_commit:
|
|
self.osd._move.emit("move-down")
|
|
mock_move_down.assert_called_with(self.model[1])
|
|
set_incremental.assert_has_calls([unittest.mock.call(False),
|
|
unittest.mock.call(True)])
|
|
mock_commit.assert_called_once()
|
|
|
|
set_incremental.reset_mock()
|
|
with unittest.mock.patch.object(self.playlist,
|
|
"move_track_up") as mock_move_up:
|
|
with unittest.mock.patch.object(self.sql, "commit") as mock_commit:
|
|
self.osd._move.emit("move-up")
|
|
mock_move_up.assert_called_with(self.model[1])
|
|
set_incremental.assert_has_calls([unittest.mock.call(False),
|
|
unittest.mock.call(True)])
|
|
mock_commit.assert_called_once()
|
|
|
|
def test_move_buttons_sensitive(self):
|
|
"""Test the move button sensitivity."""
|
|
self.assertFalse(self.osd._move.get_sensitive())
|
|
|
|
self.osd.playlist = self.playlist
|
|
self.selection.select_item(0, True)
|
|
self.assertTrue(self.osd._move.get_sensitive())
|
|
self.assertTrue(self.osd._move.can_move_down)
|
|
self.assertFalse(self.osd._move.can_move_up)
|
|
|
|
self.selection.select_item(1, True)
|
|
self.assertTrue(self.osd._move.get_sensitive())
|
|
self.assertTrue(self.osd._move.can_move_down)
|
|
self.assertTrue(self.osd._move.can_move_up)
|
|
|
|
self.selection.select_item(2, True)
|
|
self.assertTrue(self.osd._move.get_sensitive())
|
|
self.assertFalse(self.osd._move.can_move_down)
|
|
self.assertTrue(self.osd._move.can_move_up)
|
|
|
|
self.selection.select_item(1, False)
|
|
self.assertFalse(self.osd._move.get_sensitive())
|
|
|
|
def test_move_buttons_visible(self):
|
|
"""Test the move button visibility."""
|
|
self.assertFalse(self.osd._move.get_visible())
|
|
|
|
self.selection.select_item(0, True)
|
|
self.assertFalse(self.osd._move.get_visible())
|
|
|
|
self.osd.playlist = self.playlist
|
|
self.selection.select_item(1, True)
|
|
self.assertTrue(self.osd._move.get_visible())
|
|
|
|
self.db_plist.tracks_movable = False
|
|
self.selection.select_item(2, True)
|
|
self.assertFalse(self.osd._move.get_visible())
|
|
|
|
def test_selection_properties(self):
|
|
"""Test updating properties when the selection changes."""
|
|
self.assertFalse(self.osd.have_selected)
|
|
self.assertEqual(self.osd.n_selected, 0)
|
|
|
|
self.selection.select_item(1, True)
|
|
self.assertTrue(self.osd.have_selected)
|
|
self.assertEqual(self.osd.n_selected, 1)
|
|
|
|
def test_clear_selection(self):
|
|
"""Test the clear_selection() function."""
|
|
self.selection.select_item(1, True)
|
|
self.osd.clear_selection()
|
|
self.assertEqual(self.selection.get_selection().get_size(), 0)
|
|
self.assertEqual(self.osd.n_selected, 0)
|
|
self.assertFalse(self.osd.have_selected)
|
|
|
|
self.osd.playlist = self.playlist
|
|
self.assertEqual(self.selection.get_selection().get_size(), 0)
|
|
self.assertEqual(self.osd.n_selected, 0)
|
|
self.assertFalse(self.osd.have_selected)
|
|
|
|
def test_reset(self):
|
|
"""Test the reset() function."""
|
|
self.osd.have_selected = True
|
|
|
|
with unittest.mock.patch.object(self.selection,
|
|
"unselect_all") as mock_unselect:
|
|
self.osd.reset()
|
|
mock_unselect.assert_called()
|
|
self.assertFalse(self.osd.have_selected)
|