mirror of
				https://github.com/KevinMidboe/spotify-downloader.git
				synced 2025-10-29 18:00:15 +00:00 
			
		
		
		
	Add tests for encoders
and some refactoring
This commit is contained in:
		| @@ -1,13 +1,15 @@ | |||||||
| import subprocess | import subprocess | ||||||
| import os | import os | ||||||
| from logzero import logger as log | from logzero import logger as log | ||||||
|  |  | ||||||
| from spotdl.encode import EncoderBase | from spotdl.encode import EncoderBase | ||||||
| from spotdl.encode.exceptions import EncoderNotFoundError | from spotdl.encode.exceptions import EncoderNotFoundError | ||||||
| from spotdl.encode.exceptions import AvconvNotFoundError | from spotdl.encode.exceptions import AvconvNotFoundError | ||||||
|  |  | ||||||
|  |  | ||||||
| class EncoderAvconv(EncoderBase): | class EncoderAvconv(EncoderBase): | ||||||
|     def __init__(self, encoder_path="avconv"): |     def __init__(self, encoder_path="avconv"): | ||||||
|         print("Using EncoderAvconv is deprecated and will be removed" |         print("Using EncoderAvconv is deprecated and will be removed", | ||||||
|               "in future versions. Use EncoderFFmpeg instead.") |               "in future versions. Use EncoderFFmpeg instead.") | ||||||
|         encoder_path = encoder_path |         encoder_path = encoder_path | ||||||
|         _loglevel = "-loglevel 0" |         _loglevel = "-loglevel 0" | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								spotdl/encode/encoders/tests/test_avconv.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								spotdl/encode/encoders/tests/test_avconv.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | from spotdl.encode import EncoderBase | ||||||
|  | from spotdl.encode.exceptions import AvconvNotFoundError | ||||||
|  | from spotdl.encode.encoders import EncoderAvconv | ||||||
|  |  | ||||||
|  | import pytest | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestEncoderAvconv: | ||||||
|  |     def test_subclass(self): | ||||||
|  |         assert issubclass(EncoderAvconv, EncoderBase) | ||||||
|  |  | ||||||
|  |     def test_avconv_not_found_error(self): | ||||||
|  |         with pytest.raises(AvconvNotFoundError): | ||||||
|  |             EncoderAvconv(encoder_path="/a/nonexistent/path") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestEncodingDefaults: | ||||||
|  |     def encode_command(input_file, output_file): | ||||||
|  |         command = [ | ||||||
|  |             'avconv', '-y', '-loglevel', '0', | ||||||
|  |             '-i', input_file, | ||||||
|  |             '-ab', '192k', | ||||||
|  |             output_file, | ||||||
|  |         ] | ||||||
|  |         return command | ||||||
|  |  | ||||||
|  |     @pytest.mark.parametrize("files, expected_command", [ | ||||||
|  |         (("test.m4a", "test.mp3"), encode_command("test.m4a", "test.mp3")), | ||||||
|  |         (("abc.m4a", "cba.webm"), encode_command("abc.m4a", "cba.webm")), | ||||||
|  |         (("bla bla.m4a", "ble ble.m4a"), encode_command("bla bla.m4a", "ble ble.m4a")), | ||||||
|  |         (("😛.m4a", "• tongue.flac"), encode_command("😛.m4a", "• tongue.flac")), | ||||||
|  |     ]) | ||||||
|  |     def test_generate_encode_command(self, files, expected_command): | ||||||
|  |         encoder = EncoderAvconv() | ||||||
|  |         assert encoder._generate_encode_command(*files) == expected_command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestEncodingInDebugMode: | ||||||
|  |     def debug_encode_command(input_file, output_file): | ||||||
|  |         command = [ | ||||||
|  |             'avconv', '-y', '-loglevel', 'debug', | ||||||
|  |             '-i', input_file, | ||||||
|  |             '-ab', '192k', | ||||||
|  |             output_file, | ||||||
|  |         ] | ||||||
|  |         return command | ||||||
|  |  | ||||||
|  |     @pytest.mark.parametrize("files, expected_command", [ | ||||||
|  |         (("test.m4a", "test.mp3"), debug_encode_command("test.m4a", "test.mp3")), | ||||||
|  |         (("abc.m4a", "cba.webm"), debug_encode_command("abc.m4a", "cba.webm")), | ||||||
|  |         (("bla bla.m4a", "ble ble.m4a"), debug_encode_command("bla bla.m4a", "ble ble.m4a")), | ||||||
|  |         (("😛.m4a", "• tongue.flac"), debug_encode_command("😛.m4a", "• tongue.flac")), | ||||||
|  |     ]) | ||||||
|  |     def test_generate_encode_command_with_debug(self, files, expected_command): | ||||||
|  |         encoder = EncoderAvconv() | ||||||
|  |         encoder.set_debuglog() | ||||||
|  |         assert encoder._generate_encode_command(*files) == expected_command | ||||||
|  |  | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| from spotdl.encode import EncoderBase | from spotdl.encode import EncoderBase | ||||||
| # from spotdl.encode import exceptions | from spotdl.encode.exceptions import FFmpegNotFoundError | ||||||
| from spotdl.encode.encoders import EncoderFFmpeg | from spotdl.encode.encoders import EncoderFFmpeg | ||||||
|  |  | ||||||
| import pytest | import pytest | ||||||
| @@ -9,6 +9,10 @@ class TestEncoderFFmpeg: | |||||||
|     def test_subclass(self): |     def test_subclass(self): | ||||||
|         assert issubclass(EncoderFFmpeg, EncoderBase) |         assert issubclass(EncoderFFmpeg, EncoderBase) | ||||||
|  |  | ||||||
|  |     def test_ffmpeg_not_found_error(self): | ||||||
|  |         with pytest.raises(FFmpegNotFoundError): | ||||||
|  |             EncoderFFmpeg(encoder_path="/a/nonexistent/path") | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestEncodingDefaults: | class TestEncodingDefaults: | ||||||
|     def m4a_to_mp3_encoder(input_file, output_file): |     def m4a_to_mp3_encoder(input_file, output_file): | ||||||
|   | |||||||
| @@ -1,8 +1,11 @@ | |||||||
| from spotdl.encode import EncoderBase | from spotdl.encode import EncoderBase | ||||||
|  | from spotdl.encode.exceptions import EncoderNotFoundError | ||||||
|  |  | ||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
| def test_abstract_base_class_encoderbase(): |  | ||||||
|  | class TestAbstractBaseClass: | ||||||
|  |     def test_error_abstract_base_class_encoderbase(self): | ||||||
|         encoder_path = "ffmpeg" |         encoder_path = "ffmpeg" | ||||||
|         _loglevel = "-hide_banner -nostats -v panic" |         _loglevel = "-hide_banner -nostats -v panic" | ||||||
|         _additional_arguments = ["-b:a", "192k", "-vn"] |         _additional_arguments = ["-b:a", "192k", "-vn"] | ||||||
| @@ -11,3 +14,88 @@ def test_abstract_base_class_encoderbase(): | |||||||
|             # This abstract base class must be inherited from |             # This abstract base class must be inherited from | ||||||
|             # for instantiation |             # for instantiation | ||||||
|             EncoderBase(encoder_path, _loglevel, _additional_arguments) |             EncoderBase(encoder_path, _loglevel, _additional_arguments) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def test_inherit_abstract_base_class_encoderbase(self): | ||||||
|  |         class EncoderKid(EncoderBase): | ||||||
|  |             def __init__(self, encoder_path, _loglevel, _additional_arguments): | ||||||
|  |                 super().__init__(encoder_path, _loglevel, _additional_arguments) | ||||||
|  |  | ||||||
|  |             def _generate_encode_command(self): | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |             def _generate_encoding_arguments(self): | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |             def get_encoding(self): | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |             def re_encode(self): | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |             def set_argument(self): | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |             def set_debuglog(self): | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         encoder_path = "ffmpeg" | ||||||
|  |         _loglevel = "-hide_banner -nostats -v panic" | ||||||
|  |         _additional_arguments = ["-b:a", "192k", "-vn"] | ||||||
|  |  | ||||||
|  |         EncoderKid(encoder_path, _loglevel, _additional_arguments) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestMethods: | ||||||
|  |     class EncoderKid(EncoderBase): | ||||||
|  |         def __init__(self, encoder_path, _loglevel, _additional_arguments): | ||||||
|  |             super().__init__(encoder_path, _loglevel, _additional_arguments) | ||||||
|  |  | ||||||
|  |         def _generate_encode_command(self, input_file, output_file): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |         def _generate_encoding_arguments(self, input_encoding, output_encoding): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |         def get_encoding(self, filename): | ||||||
|  |             return super().get_encoding(filename) | ||||||
|  |  | ||||||
|  |         def re_encode(self, input_encoding, output_encoding): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |         def set_argument(self, argument): | ||||||
|  |             super().set_argument(argument) | ||||||
|  |  | ||||||
|  |         def set_debuglog(self): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @pytest.fixture(scope="module") | ||||||
|  |     def encoderkid(self): | ||||||
|  |         encoder_path = "ffmpeg" | ||||||
|  |         _loglevel = "-hide_banner -nostats -v panic" | ||||||
|  |         _additional_arguments = [] | ||||||
|  |  | ||||||
|  |         encoderkid = self.EncoderKid(encoder_path, _loglevel, _additional_arguments) | ||||||
|  |         return encoderkid | ||||||
|  |  | ||||||
|  |     def test_set_argument(self, encoderkid): | ||||||
|  |         encoderkid.set_argument("-parameter argument") | ||||||
|  |         assert encoderkid._additional_arguments == [ | ||||||
|  |             "-parameter", | ||||||
|  |             "argument", | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |     @pytest.mark.parametrize("filename, encoding", [ | ||||||
|  |         ("example.m4a", "m4a"), | ||||||
|  |         ("exampley.mp3", "mp3"), | ||||||
|  |         ("test 123.webm", "webm"), | ||||||
|  |         ("flakey.flac", "flac"), | ||||||
|  |     ]) | ||||||
|  |     def test_get_encoding(self, encoderkid, filename, encoding): | ||||||
|  |         assert encoderkid.get_encoding(filename) == encoding | ||||||
|  |  | ||||||
|  |     def test_encoder_not_found_error(self): | ||||||
|  |         with pytest.raises(EncoderNotFoundError): | ||||||
|  |             self.EncoderKid("/a/nonexistent/path", "0", []) | ||||||
|   | |||||||
| @@ -6,6 +6,9 @@ import pytest | |||||||
|  |  | ||||||
|  |  | ||||||
| class TestEncoderNotFoundSubclass: | class TestEncoderNotFoundSubclass: | ||||||
|  |     def test_encoder_not_found_subclass(self): | ||||||
|  |         assert issubclass(FFmpegNotFoundError, Exception) | ||||||
|  |  | ||||||
|     def test_ffmpeg_not_found_subclass(self): |     def test_ffmpeg_not_found_subclass(self): | ||||||
|         assert issubclass(FFmpegNotFoundError, EncoderNotFoundError) |         assert issubclass(FFmpegNotFoundError, EncoderNotFoundError) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ from abc import abstractmethod | |||||||
|  |  | ||||||
| class LyricBase(ABC): | class LyricBase(ABC): | ||||||
|     @abstractmethod |     @abstractmethod | ||||||
|     def __init__(self, artist, song): |     def __init__(self, artist, track): | ||||||
|         pass |         pass | ||||||
|  |  | ||||||
|     @abstractmethod |     @abstractmethod | ||||||
|   | |||||||
| @@ -8,13 +8,13 @@ BASE_URL = "https://genius.com" | |||||||
|  |  | ||||||
|  |  | ||||||
| class Genius(LyricBase): | class Genius(LyricBase): | ||||||
|     def __init__(self, artist, song): |     def __init__(self, artist, track): | ||||||
|         self.artist = artist |         self.artist = artist | ||||||
|         self.song = song |         self.track = track | ||||||
|         self.base_url = BASE_URL |         self.base_url = BASE_URL | ||||||
|  |  | ||||||
|     def _guess_lyric_url(self): |     def _guess_lyric_url(self): | ||||||
|         query = "/{} {} lyrics".format(self.artist, self.song) |         query = "/{} {} lyrics".format(self.artist, self.track) | ||||||
|         query = query.replace(" ", "-") |         query = query.replace(" ", "-") | ||||||
|         encoded_query = urllib.request.quote(query) |         encoded_query = urllib.request.quote(query) | ||||||
|         lyric_url = self.base_url + encoded_query |         lyric_url = self.base_url + encoded_query | ||||||
| @@ -28,7 +28,7 @@ class Genius(LyricBase): | |||||||
|         except urllib.request.HTTPError: |         except urllib.request.HTTPError: | ||||||
|             raise LyricsNotFoundError( |             raise LyricsNotFoundError( | ||||||
|                 "Could not find lyrics for {} - {} at URL: {}".format( |                 "Could not find lyrics for {} - {} at URL: {}".format( | ||||||
|                     self.artist, self.song, url |                     self.artist, self.track, url | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
|         else: |         else: | ||||||
|   | |||||||
| @@ -5,13 +5,13 @@ from spotdl.lyrics.exceptions import LyricsNotFoundError | |||||||
|  |  | ||||||
|  |  | ||||||
| class LyricWikia(LyricBase): | class LyricWikia(LyricBase): | ||||||
|     def __init__(self, artist, song): |     def __init__(self, artist, track): | ||||||
|         self.artist = artist |         self.artist = artist | ||||||
|         self.song = song |         self.track = track | ||||||
|  |  | ||||||
|     def get_lyrics(self, linesep="\n", timeout=None): |     def get_lyrics(self, linesep="\n", timeout=None): | ||||||
|         try: |         try: | ||||||
|             lyrics = lyricwikia.get_lyrics(self.artist, self.song, linesep, timeout) |             lyrics = lyricwikia.get_lyrics(self.artist, self.track, linesep, timeout) | ||||||
|         except lyricwikia.LyricsNotFound as e: |         except lyricwikia.LyricsNotFound as e: | ||||||
|             raise LyricsNotFoundError(e.args[0]) |             raise LyricsNotFoundError(e.args[0]) | ||||||
|         else: |         else: | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ class TestGenius: | |||||||
|  |  | ||||||
|     @pytest.fixture(scope="module") |     @pytest.fixture(scope="module") | ||||||
|     def track(self): |     def track(self): | ||||||
|         return Genius("artist", "song") |         return Genius("artist", "track") | ||||||
|  |  | ||||||
|     def test_base_url(self, track): |     def test_base_url(self, track): | ||||||
|         assert track.base_url == "https://genius.com" |         assert track.base_url == "https://genius.com" | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								spotdl/lyrics/tests/test_exceptions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spotdl/lyrics/tests/test_exceptions.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | from spotdl.lyrics.exceptions import LyricsNotFoundError | ||||||
|  |  | ||||||
|  | def test_lyrics_not_found_subclass(): | ||||||
|  |     assert issubclass(LyricsNotFoundError, Exception) | ||||||
|  |  | ||||||
							
								
								
									
										29
									
								
								spotdl/lyrics/tests/test_lyric_base.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								spotdl/lyrics/tests/test_lyric_base.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | from spotdl.lyrics import LyricBase | ||||||
|  |  | ||||||
|  | import pytest | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TestAbstractBaseClass: | ||||||
|  |     def test_error_abstract_base_class_lyricbase(self): | ||||||
|  |         artist = "awesome artist" | ||||||
|  |         track = "amazing track" | ||||||
|  |  | ||||||
|  |         with pytest.raises(TypeError): | ||||||
|  |             # This abstract base class must be inherited from | ||||||
|  |             # for instantiation | ||||||
|  |             LyricBase(artist, track) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def test_inherit_abstract_base_class_encoderbase(self): | ||||||
|  |         class LyricKid(LyricBase): | ||||||
|  |             def __init__(self, artist, track): | ||||||
|  |                 super().__init__(artist, track) | ||||||
|  |  | ||||||
|  |             def get_lyrics(self): | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         artist = "awesome artist" | ||||||
|  |         track = "amazing track" | ||||||
|  |  | ||||||
|  |         LyricKid(artist, track) | ||||||
		Reference in New Issue
	
	Block a user