# Copyright 2023 (c) Anna Schumaker """Tests our tag extractor class.""" import pathlib import unittest import emmental.audio.tagger _Tags = emmental.audio.tagger._Tags class TestAudioTagger(unittest.TestCase): """Test case for the Tagger.""" def setUp(self): """Set up common variables.""" self.file = pathlib.Path("/a/b/c/track.ogg") def test_init(self): """Test that the tagger was initialized properly.""" tags = dict() tagger = _Tags(self.file, tags) self.assertEqual(tagger.file, self.file) self.assertEqual(tagger.tags, tags) def test_get_album_artist(self): """Test that the album artist is tagged properly.""" tagger = _Tags(self.file, dict()) self.assertEqual(tagger.get_album_artist(), "") for (tag, artist) in [("artist", "Artist"), ("albumartist", "Album Artist")]: with self.subTest(tag=tag, artist=artist): tagger.tags[tag] = [artist] self.assertEqual(tagger.get_album_artist(), artist) def test_get_release(self): """Test that the release date is tagged properly.""" tagger = _Tags(self.file, dict()) self.assertEqual(tagger.get_release(), "") for (tag, date) in [("year", "1987"), ("date", "1988-06-17"), ("originalyear", "1986"), ("originaldate", "1985-08")]: with self.subTest(tag=tag, date=date): tagger.tags[tag] = [date] self.assertEqual(tagger.get_release(), date) def test_empty(self): """Test handling an empty tag dict.""" tagger = _Tags(self.file, dict()) self.assertEqual(tagger.album.name, "") self.assertEqual(tagger.album.mbid, "") self.assertEqual(tagger.album.artist, "") self.assertEqual(tagger.album.release, "") self.assertEqual(tagger.album.cover, pathlib.Path("/a/b/c/cover.jpg")) self.assertListEqual(tagger.album.artists, []) self.assertEqual(tagger.medium.name, "") self.assertEqual(tagger.medium.number, 1) self.assertEqual(tagger.medium.type, "") self.assertListEqual(tagger.artists, []) self.assertListEqual(tagger.genres, []) self.assertIsNone(tagger.year) def test_album(self): """Test that the album was tagged correctly.""" tagger = _Tags(self.file, {"album": ["Album Name"], "musicbrainz_releasegroupid": ["ab-cd-ef"], "albumartist": ["Album Artist"], "date": ["1988-06"]}) self.assertEqual(tagger.album.name, "Album Name") self.assertEqual(tagger.album.mbid, "ab-cd-ef") self.assertEqual(tagger.album.artist, "Album Artist") self.assertEqual(tagger.album.release, "1988-06") self.assertEqual(tagger.album.cover, pathlib.Path("/a/b/c/cover.jpg")) self.assertEqual(len(tagger.album.artists), 1) self.assertEqual(id(tagger.album.artists[0]), id(tagger.artists[0])) tagger = _Tags(self.file, {"album": ["Album Name"], "musicbrainz_releasegroupid": ["ab-cd-ef"], "albumartist": ["Album Artist"], "musicbrainz_albumartistid": ["gh-ij-kl", "mn-op-qr"], "date": ["1988-06"]}) self.assertEqual(tagger.album.name, "Album Name") self.assertEqual(tagger.album.mbid, "ab-cd-ef") self.assertEqual(tagger.album.artist, "Album Artist") self.assertEqual(tagger.album.release, "1988-06") self.assertEqual(tagger.album.cover, pathlib.Path("/a/b/c/cover.jpg")) self.assertListEqual([(a.name, a.mbid) for a in tagger.album.artists], [(None, "gh-ij-kl"), (None, "mn-op-qr")]) def test_artists(self): """Test that the artists were tagged correctly.""" tagger = _Tags(self.file, {"artist": ["Artist"], "albumartist": ["Album Artist"]}) self.assertListEqual([(a.name, a.mbid) for a in tagger.artists], [("Album Artist", ""), ("Artist", "")]) tagger = _Tags(self.file, {"artist": ["No Artist"], "artists": ["Artist", "Other Artist"], "musicbrainz_artistid": ["ab-cd-ef", "gh-ij-kl"], "albumartist": ["Album Artist", "Other Artist"], "musicbrainz_albumartistid": ["mn-op-qr", "gh-ij-kl"]}) self.assertListEqual([(a.name, a.mbid) for a in tagger.artists], [("Album Artist", "mn-op-qr"), ("Artist", "ab-cd-ef"), ("Other Artist", "gh-ij-kl")]) tagger = _Tags(self.file, {"artist": ["No Artist"], "artists": ["Artist"], "musicbrainz_artistid": ["ab-cd-ef", "gh-ij-kl"], "albumartist": ["Album Artist"], "musicbrainz_albumartistid": ["mn-op-qr", "gh-ij-kl"]}) self.assertListEqual([(a.name, a.mbid) for a in tagger.artists], [(None, "ab-cd-ef"), (None, "gh-ij-kl"), (None, "mn-op-qr")]) tagger = _Tags(self.file, {"artists": ["Artist 1", "Artist 2"], "musicbrainz_artistid": ["ab-cd-ef", "gh-ij-kl"], "albumartist": ["Artist 1 & 2"], "musicbrainz_albumartistid": ["ab-cd-ef", "gh-ij-kl"]}) self.assertListEqual([(a.name, a.mbid) for a in tagger.artists], [("Artist 1", "ab-cd-ef"), ("Artist 2", "gh-ij-kl")]) def test_medium(self): """Test that media information was tagged correctly.""" tagger = _Tags(self.file, {"discnumber": ["2"], "discsubtitle": ["Subtitle"], "media": ["CD"]}) self.assertEqual(tagger.medium.number, 2) self.assertEqual(tagger.medium.name, "Subtitle") self.assertEqual(tagger.medium.type, "CD") def test_genre(self): """Test that genres can be tagged correctly.""" genre = "Genre 1, Genre 2 / Genre 3; Genre 4" tagger = _Tags(self.file, {"genre": [genre]}) self.assertListEqual(tagger.genres, ["Genre 1", "Genre 2", "Genre 3", "Genre 4"]) genre = ["Genre 1 / Genre 2", "Genre 3; Genre 4"] reltype = ["album", "ep", "single", "compilation"] tagger = _Tags(self.file, {"genre": genre, "releasetype": reltype}) self.assertListEqual(tagger.genres, ["EP", "Genre 1", "Genre 2", "Genre 3", "Genre 4", "Single"]) def test_track(self): """Test that tracks can be tagged corretly.""" tagger = _Tags(self.file, {"artist": ["Test Artist"], "title": ["Test Title"], "tracknumber": ["2"], "musicbrainz_releasetrackid": ["ab-cd-ef"]}, 12345, 678.90) self.assertEqual(tagger.track.artist, "Test Artist") self.assertEqual(tagger.track.length, 12345) self.assertEqual(tagger.track.mbid, "ab-cd-ef") self.assertEqual(tagger.track.mtime, 678.90) self.assertEqual(tagger.track.number, 2) self.assertEqual(tagger.track.title, "Test Title") tagger = _Tags(self.file, {}) self.assertEqual(tagger.track.artist, "") self.assertEqual(tagger.track.length, 0) self.assertEqual(tagger.track.mbid, "") self.assertEqual(tagger.track.mtime, 0.0) self.assertEqual(tagger.track.number, 0) self.assertEqual(tagger.track.title, "") def test_year(self): """Test the year property.""" tagger = _Tags(self.file, {"date": ["1988-06-17"]}) self.assertEqual(tagger.year, 1988) @unittest.mock.patch("pathlib.Path.is_file") @unittest.mock.patch("pathlib.Path.stat") class TestTagFile(unittest.TestCase): """Test case for the tag_file() function.""" def test_not_file(self, mock_stat: unittest.mock.Mock(), mock_is_file: unittest.mock.Mock): """Test calling tag_file() on something other than a file.""" path = pathlib.Path("/a/b/c") mock_is_file.return_value = False self.assertIsNone(emmental.audio.tagger.tag_file(path, None)) mock_is_file.assert_called() @unittest.mock.patch("mutagen.File") def test_no_tags(self, mock_mutagen_file: unittest.mock.Mock, mock_stat: unittest.mock.Mock(), mock_is_file: unittest.mock.Mock): """Test calling tag_file() on a file that doesn't have tags.""" path = pathlib.Path("/a/b/c/notags.txt") mock_is_file.return_value = True mock_mutagen_file.return_value = None self.assertIsNone(emmental.audio.tagger.tag_file(path, None)) mock_is_file.assert_called() mock_mutagen_file.assert_called_with(path) def test_not_updated(self, mock_stat: unittest.mock.Mock, mock_is_file: unittest.mock.Mock): """Test calling tag_file() with an mtime <= mtime reported by stat.""" path = pathlib.Path("/a/b/c/track.ogg") mock_is_file.return_value = True mock_stat.return_value.st_mtime = 123.45 self.assertIsNone(emmental.audio.tagger.tag_file(path, 123.45)) self.assertIsNone(emmental.audio.tagger.tag_file(path, 246.8)) @unittest.mock.patch("mutagen.File") def test_have_tags(self, mock_mutagen_file: unittest.mock.Mock, mock_stat: unittest.mock.Mock, mock_is_file: unittest.mock.Mock): """Test calling tag_file() successfully.""" path = pathlib.Path("/a/b/c/track.ogg") mock_is_file.return_value = True mock_stat.return_value.st_mtime = 67.890 mock_mutagen_file.return_value = unittest.mock.MagicMock() mock_mutagen_file.return_value.info.length = 12345 for mtime in [None, 70.123]: with self.subTest(mtime=mtime): tags = emmental.audio.tagger.tag_file(path, None) self.assertIsInstance(tags, emmental.audio.tagger._Tags) self.assertEqual(tags.track.length, 12345) self.assertEqual(tags.track.mtime, 67.890) mock_is_file.assert_called() mock_stat.assert_called() mock_mutagen_file.assert_called_with(path)