emmental/tests/db/test_tracks.py

781 lines
35 KiB
Python

# Copyright 2022 (c) Anna Schumaker.
"""Tests our track Gio.ListModel."""
import datetime
import pathlib
import unittest
import emmental.db.tracks
import tests.util
import unittest.mock
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
class TestTrackObject(tests.util.TestCase):
"""Tests our track object."""
def setUp(self):
"""Set up common variables."""
super().setUp()
self.table = Gio.ListStore()
self.table.sql = self.sql
self.table.update = unittest.mock.Mock()
self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
self.album = self.sql.albums.create("Test Album", "Test Artist",
release="1988-06")
self.medium = self.sql.media.create(self.album, "", number=1)
self.year = self.sql.years.create(1988)
self.track = emmental.db.tracks.Track(trackid=12345, table=self.table,
libraryid=self.library.libraryid,
mediumid=self.medium.mediumid,
year=self.year.year,
path=pathlib.Path("/a/b/c.ogg"))
def test_constants(self):
"""Test constant values."""
self.assertEqual(emmental.db.tracks.PLAYED_THRESHOLD, (2 / 3))
def test_init(self):
"""Test that the Track is set up properly."""
self.assertIsInstance(self.track, emmental.db.table.Row)
self.assertEqual(self.track.table, self.table)
self.assertEqual(self.track.trackid, 12345)
self.assertEqual(self.track.primary_key, 12345)
self.assertEqual(self.track.libraryid, self.library.libraryid)
self.assertEqual(self.track.mediumid, self.medium.mediumid)
self.assertEqual(self.track.year, self.year.year)
self.assertFalse(self.track.active)
self.assertFalse(self.track.favorite)
self.assertEqual(self.track.path, pathlib.Path("/a/b/c.ogg"))
self.assertEqual(self.track.mbid, "")
self.assertEqual(self.track.title, "")
self.assertEqual(self.track.artist, "")
self.assertEqual(self.track.number, 0)
self.assertEqual(self.track.length, 0.0)
self.assertEqual(self.track.mtime, 0.0)
self.assertEqual(self.track.playcount, 0)
self.assertIsNone(self.track.added)
self.assertIsNone(self.track.laststarted)
self.assertIsNone(self.track.lastplayed)
self.assertIsNone(self.track.restarted)
def test_get_artists(self):
"""Test getting the Artist list for a Track."""
self.table.get_artists = unittest.mock.Mock(return_value=[1, 2, 3])
self.assertListEqual(self.track.get_artists(), [1, 2, 3])
self.table.get_artists.assert_called_with(self.track)
def test_get_genres(self):
"""Test getting the Genre list for a Track."""
self.table.get_genres = unittest.mock.Mock(return_value=[1, 2, 3])
self.assertListEqual(self.track.get_genres(), [1, 2, 3])
self.table.get_genres.assert_called_with(self.track)
def test_get_library(self):
"""Test getting the Library associated with a Track."""
self.assertEqual(self.track.get_library(), self.library)
def test_get_medium(self):
"""Test getting a Medium playlist."""
self.assertEqual(self.track.get_medium(), self.medium)
def test_get_year(self):
"""Test getting a Year playlist."""
self.assertEqual(self.track.get_year(), self.year)
def test_restart(self):
"""Test the Track.restart() function."""
self.table.restart_track = unittest.mock.Mock()
self.track.restart()
self.table.restart_track.assert_called_with(self.track)
def test_start(self):
"""Test the Track.start() function."""
self.table.start_track = unittest.mock.Mock()
self.track.start()
self.table.start_track.assert_called_with(self.track)
def test_stop(self):
"""Test the Track.stop() function."""
self.table.stop_track = unittest.mock.Mock()
self.track.length = 3
self.track.stop(0)
self.table.stop_track.assert_called_with(self.track, False)
self.track.stop(2.5)
self.table.stop_track.assert_called_with(self.track, True)
def test_update_properties(self):
"""Test updating track properties."""
now = datetime.datetime.now()
self.track.update_properties(trackid=1, libraryid=1, active=True,
path=pathlib.Path("/a/b/c.ogg"),
playcount=1, laststarted=now,
lastplayed=now, restarted=now)
self.table.update.assert_not_called()
self.track.update_properties(mediumid=2, favorite=True, year=1985,
mbid="ab-cd-ef", title="New Title",
artist="New Artist", number=2,
length=12.345, mtime=67.890)
self.table.update.assert_has_calls(
[unittest.mock.call(self.track, "mediumid", 2),
unittest.mock.call(self.track, "favorite", True),
unittest.mock.call(self.track, "year", 1985),
unittest.mock.call(self.track, "mbid", "ab-cd-ef"),
unittest.mock.call(self.track, "title", "New Title"),
unittest.mock.call(self.track, "artist", "New Artist"),
unittest.mock.call(self.track, "number", 2),
unittest.mock.call(self.track, "length", 12.345),
unittest.mock.call(self.track, "mtime", 67.890)])
self.table.update.reset_mock()
self.track.update_properties(mediumid=2, favorite=True, year=1985,
mbid="ab-cd-ef", title="New Title",
artist="New Artist", number=2,
length=12.345, mtime=67.890)
self.table.update.assert_not_called()
class TestTrackTable(tests.util.TestCase):
"""Tests our track table."""
def setUp(self):
"""Set up common variables."""
super().setUp()
self.sql.playlists.load(now=True)
self.sql.playlists.favorites.add_track = unittest.mock.Mock()
self.sql.playlists.favorites.remove_track = unittest.mock.Mock()
self.sql.playlists.most_played.reload_tracks = unittest.mock.Mock()
self.sql.playlists.previous.add_track = unittest.mock.Mock()
self.sql.playlists.previous.remove_track = unittest.mock.Mock()
self.sql.playlists.queued.remove_track = unittest.mock.Mock()
self.sql.playlists.unplayed.remove_track = unittest.mock.Mock()
self.playlists = self.sql.playlists
self.library = self.sql.libraries.create(pathlib.Path("/a/b/"))
self.album = self.sql.albums.create("Test Album", "Album Artist",
release="2022-10")
self.medium = self.sql.media.create(self.album, "Test Medium",
number=1)
self.year = self.sql.years.create(1988)
self.tracks = self.sql.tracks
def test_track_filter(self):
"""Test the tracks.Filter object."""
filter = emmental.db.tracks.Filter()
self.assertEqual(filter.get_strictness(), Gtk.FilterMatch.SOME)
filter.keys = {1, 2, 3}
self.assertEqual(filter.get_strictness(), Gtk.FilterMatch.SOME)
filter.keys = set()
self.assertEqual(filter.get_strictness(), Gtk.FilterMatch.NONE)
def test_init(self):
"""Test that the Track table is initialized properly."""
self.assertIsInstance(self.tracks, emmental.db.table.Table)
self.assertIsInstance(self.tracks.get_filter(),
emmental.db.tracks.Filter)
self.assertIsNone(self.tracks.get_model())
def test_construct(self):
"""Test constructing a new Track."""
now = datetime.datetime.now()
track = self.tracks.construct(trackid=1, year=1988,
libraryid=self.library.libraryid,
mediumid=self.medium.mediumid,
path=pathlib.Path("/a/b/c.ogg"),
mbid="ab-cd-ef", title="Title", number=1,
length=1.0, artist="Artist", mtime=1.0,
playcount=1, lastplayed=now)
self.assertIsInstance(track, emmental.db.tracks.Track)
self.assertEqual(track.table, self.tracks)
self.assertEqual(track.trackid, 1)
self.assertEqual(track.libraryid, self.library.libraryid)
self.assertEqual(track.mediumid, self.medium.mediumid)
self.assertEqual(track.year, 1988)
self.assertEqual(track.path, pathlib.Path("/a/b/c.ogg"))
self.assertEqual(track.mbid, "ab-cd-ef")
self.assertEqual(track.title, "Title")
self.assertEqual(track.number, 1)
self.assertEqual(track.length, 1.0)
self.assertEqual(track.artist, "Artist")
self.assertEqual(track.mtime, 1.0)
self.assertEqual(track.playcount, 1)
self.assertEqual(track.lastplayed, now)
self.assertFalse(track.active)
self.assertFalse(track.favorite)
self.assertIsNone(self.tracks.current_track)
def test_create(self):
"""Test creating a new Track."""
track = self.tracks.create(self.library, pathlib.Path("/a/b/c.ogg"),
self.medium, self.year)
self.assertIsInstance(track, emmental.db.tracks.Track)
self.assertEqual(track.libraryid, self.library.libraryid)
self.assertEqual(track.mediumid, self.medium.mediumid)
self.assertEqual(track.year, 1988)
self.assertEqual(track.path, pathlib.Path("/a/b/c.ogg"))
self.assertEqual(track.added, datetime.datetime.utcnow().date())
track2 = self.tracks.create(self.library, pathlib.Path("/a/b/d.ogg"),
self.medium, self.year, title="Test Track",
number=1, length=1.23, artist="Artist",
mbid="ab-cd-ef", mtime=4.56)
self.assertEqual(track2.trackid, 2)
self.assertEqual(track2.libraryid, self.library.libraryid)
self.assertEqual(track2.mediumid, self.medium.mediumid)
self.assertEqual(track2.path, pathlib.Path("/a/b/d.ogg"))
self.assertEqual(track2.title, "Test Track")
self.assertEqual(track2.number, 1)
self.assertEqual(track2.length, 1.23)
self.assertEqual(track2.artist, "Artist")
self.assertEqual(track2.mbid, "ab-cd-ef")
self.assertEqual(track2.mtime, 4.56)
track3 = self.tracks.create(self.library, pathlib.Path("/a/b/c.ogg"),
self.medium, self.year)
self.assertIsNone(track3)
cur = self.sql("SELECT COUNT(*) FROM tracks")
self.assertEqual(cur.fetchone()["COUNT(*)"], 2)
def test_create_restore(self):
"""Test restoring saved track data."""
now = datetime.datetime.utcnow()
today = now.date()
yesterday = today - datetime.timedelta(days=1)
self.sql("""INSERT INTO saved_track_data
(mbid, favorite, playcount,
lastplayed, laststarted, added)
VALUES (?, ?, ?, ? , ?, ?)""",
"ab-cd-ef", True, 42, now, now, yesterday)
track1 = self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year)
self.assertFalse(track1.favorite)
self.assertEqual(track1.playcount, 0)
self.assertIsNone(track1.lastplayed)
self.assertIsNone(track1.laststarted)
self.assertEqual(track1.added, today)
row = self.sql("SELECT COUNT(*) FROM saved_track_data").fetchone()
self.assertEqual(row["COUNT(*)"], 1)
track2 = self.tracks.create(self.library, pathlib.Path("/a/b/2.ogg"),
self.medium, self.year, mbid="ab-cd-ef")
self.assertTrue(track2.favorite)
self.assertEqual(track2.playcount, 42)
self.assertEqual(track2.lastplayed, now)
self.assertEqual(track2.laststarted, now)
self.assertEqual(track2.added, yesterday)
row = self.sql("SELECT COUNT(*) FROM saved_track_data").fetchone()
self.assertEqual(row["COUNT(*)"], 0)
def test_delete(self):
"""Test deleting a Track."""
track = self.tracks.create(self.library, pathlib.Path("/a/b/c.ogg"),
self.medium, self.year)
self.assertTrue(track.delete())
self.assertIsNone(self.tracks.index(track))
cur = self.sql("SELECT COUNT(path) FROM tracks")
self.assertEqual(cur.fetchone()["COUNT(path)"], 0)
self.assertEqual(len(self.tracks), 0)
self.assertFalse(track.delete())
def test_delete_save(self):
"""Test saving track data when a track is deleted."""
now = datetime.datetime.now()
track1 = self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year, mbid="ab-cd-ef")
track2 = self.tracks.create(self.library, pathlib.Path("/a/b/2.ogg"),
self.medium, self.year)
self.sql("""UPDATE tracks
SET favorite=?, laststarted=?, lastplayed=?, playcount=?
WHERE trackid=?""", True, now, now, 42, track1.trackid)
track1.delete()
track2.delete()
rows = self.sql("SELECT * FROM saved_track_data").fetchall()
self.assertEqual(len(rows), 1)
self.assertEqual(rows[0]["mbid"], "ab-cd-ef")
self.assertEqual(rows[0]["favorite"], True)
self.assertEqual(rows[0]["laststarted"], now)
self.assertEqual(rows[0]["lastplayed"], now)
self.assertEqual(rows[0]["playcount"], 42)
self.assertEqual(rows[0]["added"], datetime.datetime.utcnow().date())
def test_filter(self):
"""Test filtering the Track table."""
self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year,
title="Title 1", artist="Test Artist")
self.tracks.create(self.library, pathlib.Path("/a/b/2.ogg"),
self.medium, self.year,
title="Title 2", artist="Test Artist")
self.tracks.filter("*1", now=True)
self.assertSetEqual(self.tracks.get_filter().keys, {1})
self.tracks.filter("*artist", now=True)
self.assertSetEqual(self.tracks.get_filter().keys, {1, 2})
self.tracks.filter("*medium", now=True)
self.assertSetEqual(self.tracks.get_filter().keys, {1, 2})
self.tracks.filter("*album", now=True)
self.assertSetEqual(self.tracks.get_filter().keys, {1, 2})
self.tracks.filter("*album artist", now=True)
self.assertSetEqual(self.tracks.get_filter().keys, {1, 2})
self.tracks.filter("2022-*", now=True)
self.assertSetEqual(self.tracks.get_filter().keys, {1, 2})
def test_load(self):
"""Test loading tracks from the database."""
now = datetime.datetime.now()
self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year)
self.tracks.create(self.library, pathlib.Path("/a/b/2.ogg"),
self.medium, self.year, title="Track 2",
number=2, length=2, artist="Test Artist",
mbid="ab-cd-ef", mtime=123.45)
self.sql("""UPDATE tracks SET active=TRUE, favorite=TRUE, playcount=3,
lastplayed=?, laststarted=? WHERE trackid=2""", now, now)
table2 = emmental.db.tracks.Table(sql=self.sql)
self.assertEqual(len(table2), 0)
table2.load(now=True)
self.assertEqual(len(table2.store), 2)
self.assertEqual(table2.current_track, table2.store[1])
for i in [0, 1]:
with self.subTest(i=i):
self.assertEqual(table2.store[i].trackid, i + 1)
self.assertEqual(table2.store[i].libraryid,
self.library.libraryid)
self.assertEqual(table2.store[i].mediumid,
self.medium.mediumid)
self.assertEqual(table2.store[i].year, self.year.year)
self.assertEqual(table2.store[i].active, bool(i))
self.assertEqual(table2.store[i].favorite, bool(i))
self.assertEqual(table2.store[i].path,
pathlib.Path(f"/a/b/{i+1}.ogg"))
self.assertEqual(table2.store[i].mbid, "ab-cd-ef" if i else "")
self.assertEqual(table2.store[i].title, "Track 2" if i else "")
self.assertEqual(table2.store[i].artist,
"Test Artist" if i else "")
self.assertEqual(table2.store[i].number, 2 if i else 0)
self.assertEqual(table2.store[i].length, 2 if i else 0)
self.assertEqual(table2.store[i].mtime, 123.45 if i else 0)
self.assertEqual(table2.store[i].playcount, 3 if i else 0)
self.assertEqual(table2.store[i].laststarted,
now if i else None)
self.assertEqual(table2.store[i].lastplayed,
now if i else None)
self.assertIsNone(table2.store[i].restarted)
def test_lookup(self):
"""Test looking up tracks in the database."""
path1 = pathlib.Path("/a/b/1.ogg")
path2 = pathlib.Path("/a/b/2.ogg")
track1 = self.tracks.create(self.library, path1,
self.medium, self.year)
track2 = self.tracks.create(self.library, path2,
self.medium, self.year, mbid="ab-cd-ef")
library2 = self.sql.libraries.create(pathlib.Path("/a/b/d"))
self.assertEqual(self.tracks.lookup(self.library, path=path1), track1)
self.assertEqual(self.tracks.lookup(path=path1), track1)
self.assertEqual(self.tracks.lookup(path=path2), track2)
self.assertIsNone(self.tracks.lookup(path="/no/such/track"))
self.assertIsNone(self.tracks.lookup(library2, path=path1))
self.assertEqual(self.tracks.lookup(self.library, mbid="ab-cd-ef"),
track2)
self.assertEqual(self.tracks.lookup(mbid="ab-cd-ef"), track2)
self.assertIsNone(self.tracks.lookup(mbid="gh-ij-kl"))
with self.assertRaises(KeyError) as error:
self.tracks.lookup(self.library)
self.assertEqual(error.value,
"Either 'path' or 'mbid' are required")
def test_map_sort_order(self):
"""Test getting a lookup table for Track sort keys."""
tracks = [self.tracks.create(self.library,
pathlib.Path(f"/a/b/{n}.ogg"),
self.medium, self.year, number=n)
for n in range(10)]
self.assertDictEqual(self.tracks.map_sort_order(""),
{t.trackid: t.trackid - 1 for t in tracks})
self.assertDictEqual(self.tracks.map_sort_order("number DESC"),
{t.trackid: 10 - t.trackid for t in tracks})
def test_update(self):
"""Test updating tracks in the database."""
track = self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year, length=10)
medium2 = self.sql.media.create(self.album, "", number=2)
y2022 = self.sql.years.create(2022)
track.update_properties(mediumid=medium2.mediumid, year=y2022.year,
favorite=True, mbid="ab-cd-ef",
title="New Title", artist="New Artist",
number=1, length=42, mtime=123.45)
self.playlists.favorites.add_track.assert_called_with(track)
cur = self.sql("""SELECT mediumid, year, favorite, mbid, title,
artist, number, length, mtime
FROM tracks WHERE trackid = ?""", track.trackid)
row = cur.fetchone()
self.assertEqual(row["mediumid"], medium2.mediumid)
self.assertEqual(row["year"], 2022)
self.assertTrue(row["favorite"])
self.assertEqual(row["mbid"], "ab-cd-ef")
self.assertEqual(row["title"], "New Title")
self.assertEqual(row["artist"], "New Artist")
self.assertEqual(row["number"], 1)
self.assertEqual(row["length"], 42)
self.assertEqual(row["mtime"], 123.45)
track.update_properties(favorite=False)
self.playlists.favorites.remove_track.assert_called_with(track)
track2 = self.tracks.create(self.library, pathlib.Path("/a/b/2.ogg"),
self.medium, self.year, length=10)
track2.active = True
row = self.sql("SELECT active FROM tracks WHERE trackid=?",
track.trackid).fetchone()
self.assertFalse(row["active"])
def test_get_artists(self):
"""Test finding the artists for a track."""
track = self.tracks.create(self.library, pathlib.Path("a/b/1.ogg"),
self.medium, self.year)
artist1 = self.sql.artists.create("Artist 1")
artist2 = self.sql.artists.create("Artist 2")
artist1.add_track(track)
artist2.add_track(track)
self.assertListEqual(self.tracks.get_artists(track),
[artist1, artist2])
def test_get_genres(self):
"""Test finding the genres for a track."""
track = self.tracks.create(self.library, pathlib.Path("a/b/1.ogg"),
self.medium, self.year)
genre1 = self.sql.genres.create("Genre 1")
genre2 = self.sql.genres.create("Genre 2")
genre1.add_track(track)
genre2.add_track(track)
self.assertListEqual(self.tracks.get_genres(track),
[genre1, genre2])
def test_mark_path_active(self):
"""Test marking a path as active."""
self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year)
self.tracks.mark_path_active(pathlib.Path("/a/b/1.ogg"))
cur = self.sql("SELECT trackid FROM tracks WHERE active=TRUE")
self.assertEqual(cur.fetchone()["trackid"], 1)
self.tracks.mark_path_active(pathlib.Path("/a/b/4.ogg"))
cur = self.sql("SELECT trackid FROM tracks WHERE active=TRUE")
self.assertIsNone(cur.fetchone())
def test_restart_track(self):
"""Test marking that a Track has restarted."""
track = self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year)
track.restart()
self.assertTrue(track.active)
self.assertGreater(datetime.datetime.utcnow(), track.restarted)
self.assertEqual(self.tracks.current_track, track)
self.playlists.previous.remove_track.assert_not_called()
def test_start_track(self):
"""Test marking that a Track has started playback."""
track = self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year)
with unittest.mock.patch.object(self.sql, "commit",
wraps=self.sql.commit) as mock_commit:
track.start()
mock_commit.assert_called()
row = self.sql("SELECT laststarted FROM tracks WHERE trackid=?",
track.trackid).fetchone()
self.assertTrue(track.active)
self.assertIsNotNone(track.laststarted)
self.assertEqual(track.laststarted, row["laststarted"])
self.assertEqual(self.tracks.current_track, track)
self.playlists.previous.remove_track.assert_called_with(track)
self.playlists.previous.add_track.assert_called_with(track)
def test_stop_started_track(self):
"""Test marking that a Track has stopped playback."""
track = self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year, length=10)
track.start()
with unittest.mock.patch.object(self.sql, "commit",
wraps=self.sql.commit) as mock_commit:
track.stop(3)
mock_commit.assert_called()
row = self.sql("SELECT lastplayed FROM tracks WHERE trackid=?",
track.trackid).fetchone()
self.assertFalse(track.active)
self.assertEqual(track.playcount, 0)
self.assertIsNone(row["lastplayed"])
self.assertIsNone(track.lastplayed)
self.assertIsNone(self.tracks.current_track)
self.playlists.most_played.reload_tracks.assert_not_called()
self.playlists.queued.remove_track.assert_not_called()
self.playlists.unplayed.remove_track.assert_not_called()
track.start()
with unittest.mock.patch.object(self.sql, "commit",
wraps=self.sql.commit) as mock_commit:
track.stop(8)
mock_commit.assert_called()
row = self.sql("""SELECT lastplayed, playcount FROM tracks
WHERE trackid=?""", track.trackid).fetchone()
self.assertEqual(row["playcount"], 1)
self.assertEqual(track.playcount, 1)
self.assertEqual(row["lastplayed"], track.laststarted)
self.assertEqual(track.lastplayed, track.laststarted)
self.playlists.most_played.reload_tracks.assert_called()
self.playlists.queued.remove_track.assert_called_with(track)
self.playlists.unplayed.remove_track.assert_called_with(track)
def test_stop_restarted_track(self):
"""Test marking that a restarted Track has stopped playback."""
track = self.tracks.create(self.library, pathlib.Path("/a/b/1.ogg"),
self.medium, self.year, length=10)
track.restart()
track.stop(3)
row = self.sql("""SELECT lastplayed, laststarted FROM tracks
WHERE trackid=?""", track.trackid).fetchone()
self.assertFalse(track.active)
self.assertEqual(track.playcount, 0)
self.assertIsNone(row["lastplayed"])
self.assertIsNone(track.lastplayed)
self.assertIsNone(row["laststarted"])
self.assertIsNone(track.laststarted)
self.assertIsNone(track.restarted)
self.assertIsNone(self.tracks.current_track)
self.playlists.most_played.reload_tracks.assert_not_called()
self.playlists.queued.remove_track.assert_not_called()
self.playlists.unplayed.remove_track.assert_not_called()
track.restart()
restarted = track.restarted
track.stop(8)
row = self.sql("""SELECT lastplayed, laststarted, playcount FROM tracks
WHERE trackid=?""", track.trackid).fetchone()
self.assertEqual(row["playcount"], 1)
self.assertEqual(track.playcount, 1)
self.assertEqual(row["lastplayed"], restarted)
self.assertEqual(track.lastplayed, restarted)
self.assertEqual(row["laststarted"], restarted)
self.assertEqual(track.laststarted, restarted)
self.playlists.most_played.reload_tracks.assert_called_with(idle=True)
self.playlists.queued.remove_track.assert_called_with(track)
self.playlists.unplayed.remove_track.assert_called_with(track)
def test_current_track(self):
"""Test the current-track and have-current-track properties."""
self.assertIsNone(self.tracks.current_track)
self.assertFalse(self.tracks.have_current_track)
track = self.tracks.construct(trackid=2, active=True)
self.assertEqual(self.tracks.current_track, track)
self.assertTrue(self.tracks.have_current_track)
self.playlists.previous.add_track.assert_called_with(track)
track2 = self.tracks.construct(trackid=2, active=True)
self.assertEqual(self.tracks.current_track, track2)
self.assertTrue(self.tracks.have_current_track)
self.playlists.previous.add_track.assert_called_with(track2)
self.playlists.previous.add_track.reset_mock()
self.tracks.current_track = None
self.assertFalse(self.tracks.have_current_track)
self.playlists.previous.add_track.assert_not_called()
def test_current_favorite(self):
"""Test the current-favorite property."""
self.assertFalse(self.tracks.current_favorite)
self.tracks.current_favorite = True
self.assertFalse(self.tracks.current_favorite)
track = self.tracks.construct(trackid=2, active=True, favorite=True)
self.assertEqual(self.tracks.current_track, track)
self.assertTrue(self.tracks.current_favorite)
track.favorite = False
self.assertFalse(self.tracks.current_favorite)
track.favorite = True
self.assertTrue(self.tracks.current_favorite)
class TestTrackIdSet(tests.util.TestCase):
"""Test our custom TrackIdSet object."""
def setUp(self):
"""Set up common variables."""
super().setUp()
self.library = self.sql.libraries.create(pathlib.Path("/a/b"))
self.album = self.sql.albums.create("Album", "Artist", "2023-03")
self.medium = self.sql.media.create(self.album, "", number=1)
self.year = self.sql.years.create(1988)
self.tracks = self.sql.tracks
self.track1 = self.tracks.create(self.library,
pathlib.Path("/a/b/1.ogg"),
self.medium, self.year)
self.track2 = self.tracks.create(self.library,
pathlib.Path("/a/b/2.ogg"),
self.medium, self.year)
self.trackids = emmental.db.tracks.TrackidSet()
def test_init(self):
"""Test that the TrackIdSet was initialized properly."""
self.assertIsInstance(self.trackids, GObject.GObject)
self.assertIsInstance(self.trackids._TrackidSet__trackids, set)
self.assertEqual(self.trackids.n_trackids, 0)
trackids2 = emmental.db.tracks.TrackidSet({1, 2, 3})
self.assertSetEqual(trackids2._TrackidSet__trackids, {1, 2, 3})
self.assertEqual(trackids2.n_trackids, 3)
def test_contains(self):
"""Test the __contains__() function."""
self.trackids.add_track(self.track1)
self.assertTrue(self.track1 in self.trackids)
self.assertFalse(self.track2 in self.trackids)
def test_len(self):
"""Test the __len__() function."""
self.assertEqual(len(self.trackids), 0)
self.trackids.add_track(self.track1)
self.assertEqual(len(self.trackids), 1)
def test_sub(self):
"""Test the __sub__() function."""
self.trackids.trackids = {1, 2, 3, 4, 5}
trackidset2 = emmental.db.tracks.TrackidSet({3, 4, 5, 6, 7})
res = self.trackids - trackidset2
self.assertIsInstance(res, emmental.db.tracks.TrackidSet)
self.assertSetEqual(res.trackids, {1, 2})
def test_add_track(self):
"""Test adding a Track to the set."""
added = unittest.mock.Mock()
self.trackids.connect("trackid-added", added)
self.trackids.add_track(self.track1)
self.assertSetEqual(self.trackids.trackids, {self.track1.trackid})
self.assertEqual(self.trackids.n_trackids, 1)
added.assert_called_with(self.trackids, self.track1.trackid)
self.trackids.add_track(self.track2)
self.assertSetEqual(self.trackids.trackids,
{self.track1.trackid, self.track2.trackid})
self.assertEqual(self.trackids.n_trackids, 2)
added.assert_called_with(self.trackids, self.track2.trackid)
added.reset_mock()
self.trackids.add_track(self.track2)
self.assertSetEqual(self.trackids.trackids,
{self.track1.trackid, self.track2.trackid})
self.assertEqual(self.trackids.n_trackids, 2)
added.assert_not_called()
@unittest.mock.patch("random.choice")
def test_random_trackid(self, mock_choice: unittest.mock.Mock):
"""Test getting a random trackid from the set."""
self.assertIsNone(self.trackids.random_trackid())
mock_choice.assert_not_called()
self.trackids.trackids = {1, 2, 3}
mock_choice.return_value = 2
self.assertEqual(self.trackids.random_trackid(), 2)
mock_choice.assert_called_with([1, 2, 3])
def test_remove_track(self):
"""Test removing a Track from the set."""
removed = unittest.mock.Mock()
self.trackids.trackids = {self.track1.trackid, self.track2.trackid}
self.trackids.connect("trackid-removed", removed)
self.trackids.remove_track(self.track1)
self.assertSetEqual(self.trackids.trackids, {self.track2.trackid})
self.assertEqual(self.trackids.n_trackids, 1)
removed.assert_called_with(self.trackids, self.track1.trackid)
removed.reset_mock()
self.trackids.remove_track(self.track1)
self.assertSetEqual(self.trackids.trackids, {self.track2.trackid})
self.assertEqual(self.trackids.n_trackids, 1)
removed.assert_not_called()
def test_trackids(self):
"""Test setting the Trackids property."""
added = unittest.mock.Mock()
removed = unittest.mock.Mock()
reset = unittest.mock.Mock()
self.trackids.connect("trackid-added", added)
self.trackids.connect("trackid-removed", removed)
self.trackids.connect("trackids-reset", reset)
self.trackids.trackids = {1, 2, 3, 4, 5}
self.assertSetEqual(self.trackids.trackids, {1, 2, 3, 4, 5})
self.assertEqual(self.trackids.n_trackids, 5)
added.assert_not_called()
removed.assert_not_called()
reset.assert_called_with(self.trackids)
reset.reset_mock()
self.trackids.trackids = {1, 2, 3, 4, 5}
self.assertSetEqual(self.trackids.trackids, {1, 2, 3, 4, 5})
added.assert_not_called()
removed.assert_not_called()
reset.assert_not_called()
self.trackids.trackids = {3, 4, 5, 6, 7}
self.assertSetEqual(self.trackids.trackids, {3, 4, 5, 6, 7})
added.assert_has_calls([unittest.mock.call(self.trackids, 6),
unittest.mock.call(self.trackids, 7)])
removed.assert_has_calls([unittest.mock.call(self.trackids, 1),
unittest.mock.call(self.trackids, 2)])
reset.assert_not_called()