Files
dl-organizer/tests/test_cli_parse.py
T
windyboyandClaude Sonnet 4.5 9814b2b917 feat: enable anime parsing and organization with dedicated templates
Anime files with SxxEyy format are now parsed and organized into
anime-specific directories using configurable templates. Files with
absolute episode numbering (no season info) are marked needs_review
for manual handling. Also removes unused imports flagged by ruff.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-09-27 11:08:15 +08:00

247 lines
8.9 KiB
Python

"""Tests for the parse CLI command."""
import json
from click.testing import CliRunner
from vlm.cli import main
class TestParseCommand:
"""Tests for vlm parse command."""
def test_parse_without_inventory_v1_schema(self, tmp_path):
"""Test parse without --inventory flag produces v1 schema."""
# Create a simple inventory CSV (without metadata)
inventory_csv = tmp_path / "inventory.csv"
inventory_csv.write_text(
"# vlm inventory\n"
"path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n"
"/library/movie/Matrix (1999).mkv,Matrix (1999).mkv,1000000,2024-01-01T00:00:00,movie,,,\n"
"/library/series/Breaking Bad S01E01.mkv,Breaking Bad S01E01.mkv,500000,2024-01-02T00:00:00,series,,,\n"
)
output_json = tmp_path / "identities.json"
runner = CliRunner()
result = runner.invoke(
main,
[
"--config",
str(tmp_path / "config.yaml"),
"parse",
"--input",
str(inventory_csv),
"--output",
str(output_json),
],
)
# Command should succeed
assert result.exit_code == 0
# Load output and verify v1 schema (no version field or version is 1.0)
with open(output_json) as f:
data = json.load(f)
# v1 schema - no vlm_schema_version or it's "1.0"
assert data.get("vlm_schema_version", "1.0") == "1.0"
# Verify no video_metadata in records
if data.get("movies"):
for movie in data["movies"]:
assert "video_metadata" not in movie
if data.get("series"):
for series in data["series"]:
assert "video_metadata" not in series
def test_parse_with_inventory_v2_schema(self, tmp_path):
"""Test parse with --inventory flag produces v2 schema with embedded metadata."""
# Create inventory CSV with full metadata
inventory_csv = tmp_path / "inventory.csv"
inventory_csv.write_text(
"# vlm inventory\n"
"path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n"
"/library/movie/Matrix (1999).mkv,Matrix (1999).mkv,2000000000,2024-01-01T10:00:00+00:00,movie,1920x1080,h264,7200.5,5000\n"
"/library/series/Breaking Bad S01E01.mkv,Breaking Bad S01E01.mkv,500000000,2024-01-02T15:00:00+00:00,series,1280x720,h264,2700.0,3000\n"
)
output_json = tmp_path / "identities.json"
runner = CliRunner()
result = runner.invoke(
main,
[
"--config",
str(tmp_path / "config.yaml"),
"parse",
"--input",
str(inventory_csv),
"--output",
str(output_json),
"--inventory",
str(inventory_csv),
],
)
# Command should succeed
assert result.exit_code == 0
assert "Loading video metadata from:" in result.output
assert "Loaded metadata for 2 files" in result.output
# Load output and verify v2 schema
with open(output_json) as f:
data = json.load(f)
# v2 schema version
assert data["vlm_schema_version"] == "2.0"
# Verify video_metadata embedded in movie record
assert len(data["movies"]) == 1
movie = data["movies"][0]
assert "video_metadata" in movie
assert movie["video_metadata"]["size_bytes"] == 2000000000
assert movie["video_metadata"]["resolution"] == "1920x1080"
assert movie["video_metadata"]["codec"] == "h264"
assert movie["video_metadata"]["duration_seconds"] == 7200.5
assert movie["video_metadata"]["bitrate_kbps"] == 5000
# Verify video_metadata embedded in series record
assert len(data["series"]) == 1
series = data["series"][0]
assert "video_metadata" in series
assert series["video_metadata"]["size_bytes"] == 500000000
assert series["video_metadata"]["resolution"] == "1280x720"
assert series["video_metadata"]["codec"] == "h264"
assert series["video_metadata"]["duration_seconds"] == 2700.0
assert series["video_metadata"]["bitrate_kbps"] == 3000
def test_parse_with_inventory_partial_metadata(self, tmp_path):
"""Test parse with inventory that has partial metadata."""
# Create inventory with some files having metadata, some not
inventory_csv = tmp_path / "inventory.csv"
inventory_csv.write_text(
"# vlm inventory\n"
"path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n"
"/library/movie/Matrix (1999).mkv,Matrix (1999).mkv,2000000000,2024-01-01T10:00:00+00:00,movie,1920x1080,h264,,\n"
"/library/movie/Inception (2010).mkv,Inception (2010).mkv,1500000000,2024-01-02T10:00:00+00:00,movie,,,\n"
)
output_json = tmp_path / "identities.json"
runner = CliRunner()
result = runner.invoke(
main,
[
"--config",
str(tmp_path / "config.yaml"),
"parse",
"--input",
str(inventory_csv),
"--output",
str(output_json),
"--inventory",
str(inventory_csv),
],
)
# Command should succeed
assert result.exit_code == 0
# Load output and verify
with open(output_json) as f:
data = json.load(f)
assert data["vlm_schema_version"] == "2.0"
assert len(data["movies"]) == 2
# First movie has partial metadata
movie1 = data["movies"][0]
assert movie1["video_metadata"]["size_bytes"] == 2000000000
assert movie1["video_metadata"]["resolution"] == "1920x1080"
assert movie1["video_metadata"]["codec"] == "h264"
assert movie1["video_metadata"]["duration_seconds"] is None
assert movie1["video_metadata"]["bitrate_kbps"] is None
# Second movie has minimal metadata
movie2 = data["movies"][1]
assert movie2["video_metadata"]["size_bytes"] == 1500000000
assert movie2["video_metadata"]["resolution"] is None
assert movie2["video_metadata"]["codec"] is None
def test_parse_anime_with_season_episode(self, tmp_path):
"""Test parse correctly parses anime files with SxxEyy format."""
inventory_csv = tmp_path / "inventory.csv"
inventory_csv.write_text(
"# vlm inventory\n"
"path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n"
"/library/anime/Naruto Shippuden S01E05.mkv,Naruto Shippuden S01E05.mkv,500000,2024-01-01T00:00:00,anime,,,\n"
)
output_json = tmp_path / "identities.json"
runner = CliRunner()
result = runner.invoke(
main,
[
"--config",
str(tmp_path / "config.yaml"),
"parse",
"--input",
str(inventory_csv),
"--output",
str(output_json),
],
)
assert result.exit_code == 0
assert "Anime: 1" in result.output
with open(output_json) as f:
data = json.load(f)
assert len(data["anime"]) == 1
anime = data["anime"][0]
assert anime["title"] == "Naruto Shippuden"
assert anime["season"] == 1
assert anime["episodes"] == [5]
assert anime["confidence"] == 0.9
assert anime["needs_review"] is False
def test_parse_anime_absolute_numbering_needs_review(self, tmp_path):
"""Test parse marks anime with absolute episode numbering as needs_review."""
inventory_csv = tmp_path / "inventory.csv"
inventory_csv.write_text(
"# vlm inventory\n"
"path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n"
"/library/anime/Naruto - 042.mkv,Naruto - 042.mkv,500000,2024-01-01T00:00:00,anime,,,\n"
)
output_json = tmp_path / "identities.json"
runner = CliRunner()
result = runner.invoke(
main,
[
"--config",
str(tmp_path / "config.yaml"),
"parse",
"--input",
str(inventory_csv),
"--output",
str(output_json),
],
)
assert result.exit_code == 0
with open(output_json) as f:
data = json.load(f)
assert len(data["anime"]) == 1
anime = data["anime"][0]
assert anime["title"] == "Naruto"
assert anime["season"] is None
assert anime["episodes"] == [42]
assert anime["needs_review"] is True