1
0
mirror of https://github.com/darkzoul5/YoutubePlaylistSync.git synced 2026-07-03 04:23:59 +03:00

Refactor test configurations and enhance testing framework

- Replace TempConfig with DummyConfig across tests for consistency
- Introduce unit tests workflow configuration
- Add pytest configuration for standardized test discovery
- Implement comprehensive tests for config loading and downloader behavior
- Clean up unused temp_config.py and related references
This commit is contained in:
2025-11-24 11:21:32 +02:00
parent 21ba87c501
commit b5ee8dbf3b
13 changed files with 170 additions and 20 deletions
+9
View File
@@ -0,0 +1,9 @@
import pytest
from tests.dummy_config import DummyConfig
@pytest.fixture
def dummy_config():
"""Return a fresh DummyConfig instance for tests to customize."""
return DummyConfig()
@@ -1,7 +1,7 @@
import os
class TempConfig:
class DummyConfig:
"""Small test configuration object used by unit and integration tests.
Adjust attributes via environment variables where appropriate.
+3 -3
View File
@@ -47,7 +47,7 @@ if bin_dir.exists():
print(f"Using local aria2c at: {aria2c_path}")
from ytplaylist.downloader import PlaylistDownloader
from tests.temp_config import TempConfig
from tests.dummy_config import DummyConfig
logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(message)s')
@@ -60,7 +60,7 @@ if not playlist_url:
print(f"Using playlist URL: {playlist_url}")
cfg_base = TempConfig()
cfg_base = DummyConfig()
# ensure yt-dlp exists
import shutil as _sh
@@ -76,7 +76,7 @@ root_tmp.mkdir(parents=True, exist_ok=True)
failed = False
for mode in MODES:
print(f"\n=== Running mode: {mode} ===")
cfg = TempConfig()
cfg = DummyConfig()
# Allow enabling verbose subprocess output from CI by setting YTPL_DEBUG=1
cfg.debug = bool(os.getenv("YTPL_DEBUG", "0") == "1")
cfg.download_mode = mode
+16 -16
View File
@@ -1,23 +1,23 @@
import logging
from ytplaylist.manager import PlaylistManager
from tests.temp_config import TempConfig
from tests.dummy_config import DummyConfig
class TestConfig(TempConfig):
playlists = [{"url": None, "save_path": "./tmp_test", "archive": "archive.txt"}]
if __name__ == '__main__':
def test_run_with_prune_disabled():
logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(message)s")
print('--- Running with prune=False ---')
cfg=TestConfig()
m=PlaylistManager(cfg, debug=False)
cfg = DummyConfig()
cfg.playlists = [{"url": None, "save_path": "tests/tmp_test", "archive": "archive.txt"}]
m = PlaylistManager(cfg, debug=False)
# should complete without raising
m.run()
print('Run complete prune=False')
print('\n--- Running with prune=True, non_interactive=True ---')
cfg2=TestConfig()
cfg2.prune=True
cfg2.non_interactive=True
m2=PlaylistManager(cfg2, debug=False)
m2.run()
print('Run complete prune=True non_interactive=True')
def test_run_with_prune_enabled_non_interactive():
logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(message)s")
cfg = DummyConfig()
cfg.playlists = [{"url": None, "save_path": "tests/tmp_test", "archive": "archive.txt"}]
cfg.prune = True
cfg.non_interactive = True
m = PlaylistManager(cfg, debug=False)
# should complete without raising
m.run()
+30
View File
@@ -0,0 +1,30 @@
import json
import shutil
from pathlib import Path
from ytplaylist.config import ConfigLoader
def test_config_loader_reads_properties(tmp_path, monkeypatch):
# create a minimal config file with known binary names that exist on PATH
cfg = {
"playlists": [{"url": "https://www.youtube.com/playlist?list=FAKE", "save_path": "./tmp", "archive": "archive.txt"}],
"yt_dlp_path": "python",
"ffmpeg_path": "python",
"aria2c_path": "python",
"max_parallel_downloads": 3,
"aria2c_connections": 2,
}
p = tmp_path / "yt-playlist-config.json"
p.write_text(json.dumps(cfg), encoding="utf-8")
# Use absolute path so ConfigLoader doesn't try to create ./config
loader = ConfigLoader(str(p))
assert loader.playlists == cfg["playlists"]
assert loader.yt_dlp_path == "python"
assert loader.ffmpeg_path == "python"
assert loader.aria2c_path == "python"
assert loader.max_parallel_downloads == 3
assert loader.aria2c_connections == 2
@@ -0,0 +1,24 @@
from pathlib import Path
from ytplaylist.downloader import PlaylistDownloader
from tests.dummy_config import DummyConfig
def test_sanitize_title_and_get_file_path(tmp_path):
cfg = DummyConfig()
playlist = {"url": None, "save_path": str(tmp_path)}
dl = PlaylistDownloader(cfg, playlist, 0)
# illegal chars should be replaced and trimmed; fallback_id used when title becomes empty
title = ' My: <>:"/\\|?*Title '
safe = dl.sanitize_title(title, "ABC123")
# ensure no illegal characters remain
assert all(c not in safe for c in dl.illegal_chars)
# empty title should return fallback id
assert dl.sanitize_title(" ", "FALLBACK") == "FALLBACK"
# get_file_path uses save_path and zero-padded index
path = dl.get_file_path(5, "SongName")
assert isinstance(path, Path)
assert path.name.startswith("005 - SongName")
+26
View File
@@ -0,0 +1,26 @@
import logging
from tests.dummy_config import DummyConfig
from ytplaylist.manager import PlaylistManager
def test_manager_warns_and_sleeps(monkeypatch, caplog):
# Avoid actually sleeping during the test
slept = {"called": False}
def fake_sleep(sec):
slept["called"] = True
# monkeypatch the sleep used inside the manager module
monkeypatch.setattr("ytplaylist.manager.time.sleep", fake_sleep)
caplog.set_level(logging.WARNING)
cfg = DummyConfig()
cfg.max_parallel_downloads = 11
cfg.aria2c_connections = 10
cfg.playlists = []
m = PlaylistManager(cfg, debug=False)
m.run()
assert slept["called"] is True
assert any("may overload your network" in rec.getMessage() for rec in caplog.records)
@@ -0,0 +1,23 @@
import logging
from ytplaylist.manager import PlaylistManager
from tests.dummy_config import DummyConfig
def test_run_with_prune_disabled():
logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(message)s")
cfg = DummyConfig()
cfg.playlists = [{"url": None, "save_path": "tests/tmp_test", "archive": "archive.txt"}]
m = PlaylistManager(cfg, debug=False)
# should complete without raising
m.run()
def test_run_with_prune_enabled_non_interactive():
logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(message)s")
cfg = DummyConfig()
cfg.playlists = [{"url": None, "save_path": "tests/tmp_test", "archive": "archive.txt"}]
cfg.prune = True
cfg.non_interactive = True
m = PlaylistManager(cfg, debug=False)
# should complete without raising
m.run()
View File
View File