# Copyright 2022 (c) Anna Schumaker. """Tests our sidebar section widget.""" import emmental.db import emmental.sidebar.section import tests.util import unittest.mock from gi.repository import Gtk class TestSection(tests.util.TestCase): """Test our sidebar section widget.""" def setUp(self): """Set up common variables.""" super().setUp() self.table = tests.util.playlist.MockTable(self.sql) self.row_type = emmental.sidebar.row.TreeRow self.section = emmental.sidebar.section.Section(self.table, self.row_type) def test_init(self): """Test that the sidebar Section is set up properly.""" self.assertIsInstance(self.section, emmental.sidebar.header.Header) self.assertIsInstance(self.section.reveal_widget, Gtk.ScrolledWindow) self.assertEqual(self.section.reveal_widget.get_policy(), (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)) self.assertTrue(self.section.has_css_class("emmental-sidebar-section")) def test_listview(self): """Test the listview widget.""" self.assertIsInstance(self.section._selection, Gtk.SingleSelection) self.assertIsInstance(self.section._factory, emmental.factory.Factory) self.assertIsInstance(self.section._listview, Gtk.ListView) self.assertEqual(self.section.table, self.table) self.assertEqual(self.section._selection.get_model(), self.table.treemodel) self.assertFalse(self.section._selection.get_autoselect()) self.assertEqual(self.section._factory.row_type, self.row_type) self.assertEqual(self.section._listview.get_model(), self.section._selection) self.assertEqual(self.section._listview.get_factory(), self.section._factory) self.assertTrue(self.section._listview.has_css_class( "navigation-sidebar")) self.assertEqual(self.section.reveal_widget.get_child(), self.section._listview) def test_progress(self): """Test that the header progress property is wired up correctly.""" self.assertFalse(self.section.pending) self.assertEqual(self.section.progress, 0.0) self.table.queue.running = True self.table.queue.progress = 0.5 self.assertTrue(self.section.pending) self.assertEqual(self.section.progress, 0.5) section2 = emmental.sidebar.section.Section(self.table, self.row_type) self.assertTrue(section2.pending) def test_do_get_subtitle(self): """Test updating the subtitle when the treemodel items change.""" with self.assertRaises(NotImplementedError): self.assertEqual(self.section.do_get_subtitle(42)) self.section.do_get_subtitle = unittest.mock.Mock() self.section.do_get_subtitle.return_value = "My Subtitle" self.table.treemodel.items_changed(0, 0, 0) self.assertEqual(self.section.subtitle, "My Subtitle") self.section.do_get_subtitle.assert_called_with(0) def test_clear_selection(self): """Test clearing the currently selected playlist.""" with unittest.mock.patch.object(self.section._selection, "set_selected") as mock_set_selected: self.section.clear_selection() mock_set_selected.assert_called_with(Gtk.INVALID_LIST_POSITION) def test_playlist_index(self): """Test finding the index of a specific playlist.""" self.section.do_get_subtitle = unittest.mock.Mock(return_value="") playlists = [self.table.create(f"Playlist {i}") for i in range(3)] for i, playlist in enumerate(playlists): with self.subTest(i=i, playlist=playlist): self.assertEqual(self.section.playlist_index(playlist), i) table2 = tests.util.playlist.MockTable(self.sql) table2.do_sql_update = unittest.mock.Mock(return_value=True) children = [table2.create(f"Child {i}") for i in range(3)] playlists[1].children = Gtk.FilterListModel.new(table2, None) for i, child in enumerate(children): child.parent = playlists[1] with self.subTest(i=i, child=child): self.assertEqual(self.section.playlist_index(child), i + 2) def test_select_playlist(self): """Test selecting a specific playlist.""" self.section.do_get_subtitle = unittest.mock.Mock(return_value="") playlist = self.table.create("Test Playlist") with unittest.mock.patch.object(self.section._listview, "scroll_to") as mock_scroll_to: self.section.select_playlist(playlist) mock_scroll_to.assert_called_with(0, Gtk.ListScrollFlags.SELECT) def test_playlist_selected(self): """Test selecting a playlist in the list.""" self.section.do_get_subtitle = unittest.mock.Mock(return_value="") playlist_selected = unittest.mock.Mock() self.section.connect("playlist-selected", playlist_selected) playlist = self.table.create("Test Playlist") self.section._selection.set_selected(0) playlist_selected.assert_called_with(self.section, playlist) playlist_selected.reset_mock() self.section.clear_selection() playlist_selected.assert_not_called() def test_playlist_activated(self): """Test activating a playlist.""" self.section.do_get_subtitle = unittest.mock.Mock(return_value="") playlist_activated = unittest.mock.Mock() self.section.connect("playlist-activated", playlist_activated) playlist = self.table.create("Test Playlist") self.section._listview.emit("activate", 0) playlist_activated.assert_called_with(self.section, playlist) class TestGroup(tests.util.TestCase): """Test our sidebar section group.""" def setUp(self): """Set up common variables.""" super().setUp() self.view = emmental.sidebar.section.View(self.sql) self.row_type = emmental.sidebar.row.TreeRow self.section1 = emmental.sidebar.section.Section(self.sql.playlists, self.row_type) self.section2 = emmental.sidebar.section.Section(self.sql.genres, self.row_type) self.section1.do_get_subtitle = unittest.mock.Mock(return_value="") self.section2.do_get_subtitle = unittest.mock.Mock(return_value="") def test_init(self): """Test that the Group is set up properly.""" self.assertIsInstance(self.view, Gtk.Box) self.assertListEqual(self.view._sections, []) self.assertEqual(self.view.sql, self.sql) self.assertEqual(self.view.get_orientation(), Gtk.Orientation.VERTICAL) def test_add(self): """Test adding sections to the Group.""" self.view.add(self.section1) self.assertListEqual(self.view._sections, [self.section1]) self.assertEqual(self.view.get_first_child(), self.section1) self.view.add(self.section2) self.assertListEqual(self.view._sections, [self.section1, self.section2]) self.assertEqual(self.section1.get_next_sibling(), self.section2) def test_current(self): """Test the current section property.""" self.view.add(self.section1) self.view.add(self.section2) self.assertIsNone(self.view.current) self.section1.active = True self.assertEqual(self.view.current, self.section1) self.section2.active = True self.assertEqual(self.view.current, self.section2) self.assertFalse(self.section1.active) def test_animation(self): """Test setting the section animation style.""" self.view.add(self.section1) self.view.add(self.section2) self.section1.active = True self.assertEqual(self.section1.animation, Gtk.RevealerTransitionType.SLIDE_DOWN) self.section2.active = True self.assertEqual(self.section2.animation, Gtk.RevealerTransitionType.SLIDE_UP) def test_playlist_activated(self): """Test responding to the section playlist-activated signal.""" self.view.add(self.section1) self.view.add(self.section2) self.assertIsNone(self.sql.active_playlist) playlist = self.sql.playlists.create("Test Playlist") self.section1.emit("playlist-activated", playlist) self.assertEqual(self.sql.active_playlist, playlist) genre = self.sql.genres.create("Test Genre") self.section2.emit("playlist-activated", genre) self.assertEqual(self.sql.active_playlist, genre) def test_selections(self): """Test the selected section & playlist properties.""" self.view.add(self.section1) self.view.add(self.section2) self.assertIsNone(self.view.selected_section) self.assertIsNone(self.view.selected_playlist) genre = self.sql.genres.create("Test Genre") self.section2.emit("playlist-selected", genre) self.assertEqual(self.view.selected_section, self.section2) self.assertEqual(self.view.selected_playlist, genre) self.section2.active = True treerow = self.section2._selection.get_selected_item() self.assertEqual(treerow.get_item(), genre) playlist = self.sql.playlists.create("Test Playlist") self.section1.emit("playlist-selected", playlist) self.assertIsNone(self.section2._selection.get_selected_item())