- 176 unit tests covering ConfigManager, FileClassifier, EpisodeRenamer, TVDBClient, MockTVDBClient, TVDBCache, and episode_matcher CLI - Tests organized in tests/ with conftest.py shared fixtures - pytest-cov configured with 90% coverage threshold in pyproject.toml - CI workflow updated with COVERAGE_CORE=sysmon for Python 3.13 compat - .gitignore updated for coverage artifacts and venv
141 lines
3.9 KiB
Python
141 lines
3.9 KiB
Python
"""Shared fixtures for Episode Matcher tests."""
|
|
import sys
|
|
import os
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
# Ensure src is importable
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_dir(tmp_path):
|
|
"""Return a temporary directory as Path."""
|
|
return tmp_path
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_video_files(tmp_path):
|
|
"""Create mock video files in temp dir and return the dir.
|
|
Uses small sizes (KB range) since actual content doesn't matter for tests.
|
|
"""
|
|
files = {
|
|
"Disc 1_t01.mkv": int(2 * 1024),
|
|
"Disc 1_t02.mkv": int(2100),
|
|
"Disc 1_t03.mkv": int(2200),
|
|
"Disc 2_t01.mkv": int(2000),
|
|
"Disc 2_t02.mkv": int(2100),
|
|
"Disc 2_t03.mkv": int(1900),
|
|
"extra_short.mkv": int(100),
|
|
}
|
|
for name, size in files.items():
|
|
fpath = tmp_path / name
|
|
fpath.write_bytes(b"\x00" * size)
|
|
return tmp_path
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_episodes():
|
|
"""Mock episode file info dicts with realistic ratios but small absolute sizes."""
|
|
return [
|
|
{
|
|
"path": Path("Disc 1_t01.mkv"),
|
|
"name": "Disc 1_t01.mkv",
|
|
"size_bytes": int(2 * 1024),
|
|
"size_gb": 2.0,
|
|
"duration_minutes": 61.0,
|
|
},
|
|
{
|
|
"path": Path("Disc 1_t02.mkv"),
|
|
"name": "Disc 1_t02.mkv",
|
|
"size_bytes": int(2100),
|
|
"size_gb": 2.1,
|
|
"duration_minutes": 55.0,
|
|
},
|
|
{
|
|
"path": Path("Disc 1_t03.mkv"),
|
|
"name": "Disc 1_t03.mkv",
|
|
"size_bytes": int(2200),
|
|
"size_gb": 2.2,
|
|
"duration_minutes": 57.0,
|
|
},
|
|
{
|
|
"path": Path("Disc 2_t01.mkv"),
|
|
"name": "Disc 2_t01.mkv",
|
|
"size_bytes": int(2000),
|
|
"size_gb": 2.0,
|
|
"duration_minutes": 55.0,
|
|
},
|
|
{
|
|
"path": Path("Disc 2_t02.mkv"),
|
|
"name": "Disc 2_t02.mkv",
|
|
"size_bytes": int(2100),
|
|
"size_gb": 2.1,
|
|
"duration_minutes": 54.0,
|
|
},
|
|
{
|
|
"path": Path("Disc 2_t03.mkv"),
|
|
"name": "Disc 2_t03.mkv",
|
|
"size_bytes": int(1900),
|
|
"size_gb": 1.9,
|
|
"duration_minutes": 52.0,
|
|
},
|
|
]
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_tvdb_episodes():
|
|
"""Mock TVDB episode data."""
|
|
return [
|
|
{"episode_number": 1, "name": "Winter Is Coming", "runtime": 61},
|
|
{"episode_number": 2, "name": "The Kingsroad", "runtime": 55},
|
|
{"episode_number": 3, "name": "Lord Snow", "runtime": 57},
|
|
{"episode_number": 4, "name": "Cripples Bastards", "runtime": 55},
|
|
{"episode_number": 5, "name": "The Wolf", "runtime": 54},
|
|
{"episode_number": 6, "name": "A Golden Crown", "runtime": 52},
|
|
{"episode_number": 7, "name": "You Win", "runtime": 57},
|
|
{"episode_number": 8, "name": "The Pointy End", "runtime": 58},
|
|
{"episode_number": 9, "name": "Baelor", "runtime": 56},
|
|
{"episode_number": 10, "name": "Fire and Blood", "runtime": 52},
|
|
]
|
|
|
|
|
|
@pytest.fixture
|
|
def disc_mapping():
|
|
"""Mock disc-to-episode mapping."""
|
|
return {1: [1, 2, 3], 2: [4, 5, 6], 3: [7, 8]}
|
|
|
|
|
|
@pytest.fixture
|
|
def config_file(tmp_path):
|
|
"""Create a config.json in temp dir."""
|
|
import json
|
|
|
|
cfg = tmp_path / "config.json"
|
|
cfg.write_text(
|
|
json.dumps(
|
|
{
|
|
"tvdb_api_key": "test_api_key_12345",
|
|
"default_episode_duration": 45,
|
|
"classification_thresholds": {
|
|
"size_threshold_ratio": 0.3,
|
|
"duration_threshold_ratio": 0.4,
|
|
},
|
|
}
|
|
)
|
|
)
|
|
return cfg
|
|
|
|
|
|
@pytest.fixture
|
|
def empty_config_file(tmp_path):
|
|
"""Create a config.json with no API key."""
|
|
import json
|
|
|
|
cfg = tmp_path / "config.json"
|
|
cfg.write_text(json.dumps({"tvdb_api_key": ""}))
|
|
return cfg
|