# Copyright 2023 (c) Anna Schumaker. """Test our Playlist Manager object.""" import io import pathlib import unittest.mock import emmental.playlist import tests.util from gi.repository import GObject @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) class TestFactory(tests.util.TestCase): """Test the Playlist Factory class.""" def setUp(self): """Set up common variables.""" super().setUp() self.sql.playlists.load(now=True) self.user_plist = self.sql.playlists.create("User Playlist") self.factory = emmental.playlist.Factory(self.sql) def test_init(self, mock_stdout: io.StringIO): """Check that the Playlist Factory is set up properly.""" self.assertIsInstance(self.factory, GObject.GObject) self.assertEqual(self.factory.sql, self.sql) def test_active(self, mock_stdout: io.StringIO): """Test the active playlist property.""" self.assertIsNone(self.factory.db_active) self.sql.set_active_playlist(self.user_plist) self.assertEqual(self.factory.db_active, self.user_plist) self.assertRegex(mock_stdout.getvalue(), "factory: active playlist is: User Playlist") self.sql.set_active_playlist(None) self.assertIsNone(self.factory.db_active) self.assertRegex(mock_stdout.getvalue(), "active playlist is: ") def test_active_playlist(self, mock_stdout: io.StringIO): """Test creating a Playlist when setting the dv_visible property.""" self.assertIsNone(self.factory.active_playlist) self.factory.db_active = self.user_plist self.assertIsInstance(self.factory.active_playlist, emmental.playlist.playlist.Playlist) self.assertEqual(self.factory.active_playlist.sql, self.sql) self.assertEqual(self.factory.active_playlist.playlist, self.user_plist) orig_id = id(self.factory.active_playlist) self.factory.db_active = self.sql.playlists.collection self.assertEqual(id(self.factory.active_playlist), orig_id) self.assertEqual(self.factory.active_playlist.playlist, self.sql.playlists.collection) active = self.factory.active_playlist self.factory.db_active = None self.assertIsNone(self.factory.active_playlist) self.assertIsNone(active.playlist) def test_active_visible_playlist(self, mock_stdout: io.StringIO): """Test setting the active playlist to the visible playlist.""" self.factory.db_visible = self.user_plist self.factory.db_active = self.user_plist self.assertEqual(id(self.factory.active_playlist), id(self.factory.visible_playlist)) self.factory.db_active = self.user_plist self.assertEqual(id(self.factory.active_playlist), id(self.factory.visible_playlist)) self.factory.db_active = self.sql.playlists.collection self.assertNotEqual(id(self.factory.active_playlist), id(self.factory.visible_playlist)) active = self.factory.active_playlist self.factory.db_active = self.user_plist self.assertEqual(id(self.factory.active_playlist), id(self.factory.visible_playlist)) self.assertIsNone(active.playlist) active = self.factory.active_playlist self.factory.db_active = None self.assertEqual(active.playlist, self.user_plist) self.assertIsNone(self.factory.active_playlist) def test_active_loop(self, mock_stdout: io.StringIO): """Test changing the loop property of the active playlist.""" notify = unittest.mock.Mock() self.factory.connect("notify::active-loop", notify) self.assertEqual(self.factory.active_loop, "None") self.factory.active_loop = "Playlist" self.assertEqual(self.factory.active_loop, "None") notify.assert_not_called() self.factory.db_active = self.user_plist self.assertEqual(self.factory.active_loop, "None") notify.assert_called() notify.reset_mock() self.factory.active_loop = "Playlist" self.assertEqual(self.user_plist.loop, "Playlist") self.assertEqual(self.factory.active_loop, "Playlist") notify.assert_called() notify.reset_mock() self.factory.active_loop = "Playlist" notify.assert_not_called() def test_active_shuffle(self, mock_stdout: io.StringIO): """Test changing the shuffle property of the active playlist.""" notify = unittest.mock.Mock() self.factory.connect("notify::active-shuffle", notify) self.assertFalse(self.factory.active_shuffle) self.factory.active_shuffle = True self.assertFalse(self.factory.active_shuffle) notify.assert_not_called() self.factory.db_active = self.user_plist self.assertFalse(self.factory.active_shuffle) notify.assert_called() notify.reset_mock() self.factory.active_shuffle = True self.assertTrue(self.user_plist.shuffle) self.assertTrue(self.factory.active_shuffle) notify.assert_called() notify.reset_mock() self.factory.active_shuffle = True notify.assert_not_called() def test_previous(self, mock_stdout: io.StringIO): """Test the previous playlist property.""" self.assertIsNone(self.factory.db_previous) self.factory.db_previous = self.sql.playlists.previous self.assertEqual(self.factory.db_previous, self.sql.playlists.previous) self.assertRegex(mock_stdout.getvalue(), r"factory: previous playlist is: Previous Tracks") self.factory.db_previous = None self.assertRegex(mock_stdout.getvalue(), "factory: previous playlist is: ") def test_previous_playlist(self, mock_stdout: io.StringIO): """Test creating a Playlist when setting the db_previous property.""" self.assertIsNone(self.factory.previous_playlist) self.factory.db_previous = self.sql.playlists.previous self.assertIsInstance(self.factory.previous_playlist, emmental.playlist.previous.Previous) self.assertEqual(self.factory.previous_playlist.sql, self.sql) self.assertEqual(self.factory.previous_playlist.playlist, self.sql.playlists.previous) previous = self.factory.previous_playlist self.factory.db_previous = None self.assertIsNone(self.factory.previous_playlist) self.assertIsNone(previous.playlist) def test_visible(self, mock_stdout: io.StringIO): """Test the visible playlist property.""" self.assertIsNone(self.factory.db_visible) self.factory.db_visible = self.user_plist self.assertEqual(self.factory.db_visible, self.user_plist) self.assertRegex(mock_stdout.getvalue(), "factory: visible playlist is: User Playlist") self.factory.db_visible = None self.assertRegex(mock_stdout.getvalue(), "factory: visible playlist is: ") def test_visible_playlist(self, mock_stdout: io.StringIO): """Test creating a Playlist when setting the db_visible property.""" self.assertIsNone(self.factory.visible_playlist) self.factory.db_visible = self.user_plist self.assertIsInstance(self.factory.visible_playlist, emmental.playlist.playlist.Playlist) self.assertEqual(self.factory.visible_playlist.sql, self.sql) self.assertEqual(self.factory.visible_playlist.playlist, self.user_plist) orig_id = id(self.factory.visible_playlist) self.factory.db_visible = self.sql.playlists.collection self.assertEqual(id(self.factory.visible_playlist), orig_id) self.assertEqual(self.factory.visible_playlist.playlist, self.sql.playlists.collection) visible = self.factory.visible_playlist self.factory.db_visible = None self.assertIsNone(self.factory.visible_playlist) self.assertIsNone(visible.playlist) def test_visible_active_playlist(self, mock_stdout: io.StringIO): """Test setting the visible playlist to the active playlist.""" self.factory.db_active = self.user_plist self.factory.db_visible = self.user_plist self.assertEqual(id(self.factory.visible_playlist), id(self.factory.active_playlist)) self.factory.db_visible = self.user_plist self.assertEqual(id(self.factory.visible_playlist), id(self.factory.active_playlist)) self.factory.db_visible = self.sql.playlists.collection self.assertNotEqual(id(self.factory.visible_playlist), id(self.factory.active_playlist)) visible = self.factory.visible_playlist self.factory.db_visible = self.user_plist self.assertEqual(id(self.factory.visible_playlist), id(self.factory.active_playlist)) self.assertIsNone(visible.playlist) visible = self.factory.visible_playlist self.factory.db_visible = None self.assertEqual(visible.playlist, self.user_plist) self.assertIsNone(self.factory.visible_playlist) def test_visible_previous_playlist(self, mock_stdout: io.StringIO): """Test setting the visible playlist to the previous playlist.""" self.factory.db_previous = self.sql.playlists.previous self.factory.db_visible = self.sql.playlists.previous self.assertEqual(id(self.factory.visible_playlist), id(self.factory.previous_playlist)) self.factory.db_visible = self.user_plist self.assertNotEqual(id(self.factory.visible_playlist), id(self.factory.previous_playlist)) @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) class TestFactoryNextPreviousTrack(tests.util.TestCase): """Test the Factory next_track() and previous_track() functions.""" def setUp(self): """Set up common variables.""" super().setUp() self.sql.playlists.load(now=True) self.user_plist = self.sql.playlists.create("User Playlist") self.factory = emmental.playlist.Factory(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.tracks = [self.sql.tracks.create(self.library, pathlib.Path(f"/a/b/{i}.ogg"), self.medium, self.year, number=i) for i in range(1, 4)] def test_can_go_next(self, mock_stdout: io.StringIO): """Test the can-go-next property.""" self.assertFalse(self.factory.can_go_next) self.sql.playlists.have_collection_tracks = True self.assertTrue(self.factory.can_go_next) self.sql.playlists.have_collection_tracks = False self.assertFalse(self.factory.can_go_next) self.factory.db_active = self.user_plist self.factory.active_playlist.can_go_next = True self.assertTrue(self.factory.can_go_next) self.factory.active_playlist.can_go_next = False self.assertFalse(self.factory.can_go_next) self.factory.db_previous = self.sql.playlists.previous self.factory.previous_playlist.can_go_forward = True self.assertTrue(self.factory.can_go_next) self.factory.previous_playlist.can_go_forward = False self.assertFalse(self.factory.can_go_next) def test_can_go_previous(self, mock_stdout: io.StringIO): """Test the can-go-previous property.""" self.assertFalse(self.factory.can_go_previous) self.factory.db_previous = self.sql.playlists.previous self.assertFalse(self.factory.can_go_previous) self.tracks[0].start() self.assertFalse(self.factory.can_go_previous) self.tracks[1].start() self.assertTrue(self.factory.can_go_previous) self.factory.db_previous = None self.assertFalse(self.factory.can_go_previous) self.tracks[2].start() self.assertFalse(self.factory.can_go_previous) def test_next_track(self, mock_stdout: io.StringIO): """Test the next_track() function.""" self.sql.set_active_playlist(None) self.assertTupleEqual(self.factory.next_track(), (None, "track", False)) self.assertEqual(self.sql.active_playlist, self.sql.playlists.collection) self.sql.set_active_playlist(self.user_plist) self.user_plist.add_track(self.tracks[0]) self.user_plist.add_track(self.tracks[1]) self.assertTupleEqual(self.factory.next_track(), (self.tracks[0], "track", False)) self.assertTupleEqual(self.factory.next_track(), (self.tracks[1], "track", False)) self.sql.playlists.collection.add_track(self.tracks[0]) self.assertTupleEqual(self.factory.next_track(), (self.tracks[0], "track", False)) self.assertEqual(self.factory.db_active, self.sql.playlists.collection) self.assertEqual(self.sql.active_playlist, self.sql.playlists.collection) self.album.add_track(self.tracks[2]) self.factory.db_active = self.album self.assertTupleEqual(self.factory.next_track(), (self.tracks[2], "album", False)) self.medium.add_track(self.tracks[2]) self.factory.db_active = self.medium self.assertTupleEqual(self.factory.next_track(), (self.tracks[2], "album", False)) def test_next_track_user(self, mock_stdout: io.StringIO): """Test calling next_track() with user=True.""" self.factory.db_active = self.user_plist self.factory.db_previous = self.sql.playlists.previous self.user_plist.add_track(self.tracks[2]) self.tracks[0].start() self.tracks[1].start() self.factory.previous_track() self.assertEqual(self.factory.next_track(user=True), (self.tracks[1], "track", True)) self.assertEqual(self.factory.next_track(user=True), (self.tracks[2], "track", False)) def test_previous_track(self, mock_stdout: io.StringIO): """Test the previous_track() function.""" self.assertIsNone(self.factory.previous_track()) self.factory.db_previous = self.sql.playlists.previous self.assertIsNone(self.factory.previous_track()) self.tracks[0].start() self.assertIsNone(self.factory.previous_track()) self.tracks[1].start() self.assertEqual(self.factory.previous_track(), self.tracks[0]) self.assertIsNone(self.factory.previous_track()) self.tracks[2].start() self.assertEqual(self.factory.previous_track(), self.tracks[1]) self.assertEqual(self.factory.previous_track(), self.tracks[0]) self.assertIsNone(self.factory.previous_track()) def test_track_requested(self, mock_stdout: io.StringIO): """Test the track-requested signal.""" requested = unittest.mock.Mock() self.factory.connect("track-requested", requested) self.user_plist.add_track(self.tracks[0]) self.factory.db_visible = self.user_plist self.factory.visible_playlist.request_track(self.tracks[0]) requested.assert_called_with(self.factory, self.tracks[0], "track", False) self.album.add_track(self.tracks[0]) self.factory.db_visible = self.album self.factory.visible_playlist.request_track(self.tracks[0]) requested.assert_called_with(self.factory, self.tracks[0], "album", False) self.tracks[0].start() self.factory.db_visible = self.sql.playlists.previous self.factory.visible_playlist.request_track(self.tracks[0]) requested.assert_called_with(self.factory, self.tracks[0], "track", True) self.medium.add_track(self.tracks[0]) self.factory.db_visible = self.medium self.factory.visible_playlist.request_track(self.tracks[0]) requested.assert_called_with(self.factory, self.tracks[0], "album", False)