emmental/tests/tracklist/test_selection.py

321 lines
13 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 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.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()
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])])
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:
self.selection.select_all()
self.osd._remove.emit("clicked")
mock_remove.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[0]),
unittest.mock.call(self.model[1]),
unittest.mock.call(self.model[2])])
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)