246 lines
11 KiB
Python
246 lines
11 KiB
Python
# 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)
|