344 lines
13 KiB
Python
344 lines
13 KiB
Python
"""Integration tests for CLI report commands.
|
|
|
|
Tests the report commands to ensure they properly wire to the Report Generator.
|
|
"""
|
|
|
|
import json
|
|
import csv
|
|
from pathlib import Path
|
|
from datetime import datetime, timezone
|
|
from click.testing import CliRunner
|
|
from vlm.cli import main
|
|
|
|
|
|
class TestCLIReports:
|
|
"""Test CLI report commands."""
|
|
|
|
def test_report_inventory_csv(self, tmp_path):
|
|
"""Test inventory report generation in CSV format."""
|
|
# Create test inventory CSV
|
|
inventory_file = tmp_path / "inventory.csv"
|
|
with open(inventory_file, 'w', encoding='utf-8') as f:
|
|
f.write("# Generated: 2024-01-01T00:00:00\n")
|
|
f.write("# Library Root: /test/library\n")
|
|
f.write("path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n")
|
|
f.write("/test/library/movie/Movie1.mkv,Movie1.mkv,1000000,2024-01-01T00:00:00,movie,1920x1080,h264,7200,5000\n")
|
|
f.write("/test/library/series/Show.S01E01.mkv,Show.S01E01.mkv,800000,2024-01-01T00:00:00,series,1280x720,h264,2700,3000\n")
|
|
|
|
# Run command
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, ['report', 'inventory', '--input', str(inventory_file), '--format', 'csv'])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert "Loaded 2 files" in result.output
|
|
assert "Movie1.mkv" in result.output
|
|
assert "Show.S01E01.mkv" in result.output
|
|
|
|
def test_report_inventory_json(self, tmp_path):
|
|
"""Test inventory report generation in JSON format."""
|
|
# Create test inventory CSV
|
|
inventory_file = tmp_path / "inventory.csv"
|
|
with open(inventory_file, 'w', encoding='utf-8') as f:
|
|
f.write("# Generated: 2024-01-01T00:00:00\n")
|
|
f.write("# Library Root: /test/library\n")
|
|
f.write("path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n")
|
|
f.write("/test/library/movie/Movie1.mkv,Movie1.mkv,1000000,2024-01-01T00:00:00,movie,,,\n")
|
|
|
|
# Run command with output file
|
|
output_file = tmp_path / "inventory_report.json"
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'inventory',
|
|
'--input', str(inventory_file),
|
|
'--format', 'json',
|
|
'--output', str(output_file)
|
|
])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert output_file.exists()
|
|
|
|
# Verify JSON content
|
|
with open(output_file, 'r') as f:
|
|
data = json.load(f)
|
|
|
|
assert data['metadata']['file_count'] == 1
|
|
assert len(data['files']) == 1
|
|
assert data['files'][0]['filename'] == 'Movie1.mkv'
|
|
|
|
def test_report_completeness_text(self, tmp_path):
|
|
"""Test completeness report generation in text format."""
|
|
# Create test analysis JSON
|
|
analysis_file = tmp_path / "analysis.json"
|
|
analysis_data = {
|
|
"metadata": {
|
|
"generated": "2024-01-01T00:00:00",
|
|
"source_identities": "identities.json",
|
|
"total_movies": 0,
|
|
"total_series": 3
|
|
},
|
|
"completeness": [
|
|
{
|
|
"series_title": "Breaking Bad",
|
|
"season": 1,
|
|
"episodes_found": [1, 2, 4],
|
|
"episodes_missing": [3]
|
|
}
|
|
],
|
|
"duplicates": []
|
|
}
|
|
|
|
with open(analysis_file, 'w') as f:
|
|
json.dump(analysis_data, f)
|
|
|
|
# Run command
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'completeness',
|
|
'--input', str(analysis_file),
|
|
'--format', 'text'
|
|
])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert "Loaded 1 series with gaps" in result.output
|
|
assert "Breaking Bad" in result.output
|
|
assert "Episodes missing:" in result.output
|
|
|
|
def test_report_completeness_json(self, tmp_path):
|
|
"""Test completeness report generation in JSON format."""
|
|
# Create test analysis JSON
|
|
analysis_file = tmp_path / "analysis.json"
|
|
analysis_data = {
|
|
"metadata": {},
|
|
"completeness": [
|
|
{
|
|
"series_title": "The Wire",
|
|
"season": 1,
|
|
"episodes_found": [1, 3],
|
|
"episodes_missing": [2]
|
|
}
|
|
],
|
|
"duplicates": []
|
|
}
|
|
|
|
with open(analysis_file, 'w') as f:
|
|
json.dump(analysis_data, f)
|
|
|
|
# Run command with output file
|
|
output_file = tmp_path / "completeness_report.json"
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'completeness',
|
|
'--input', str(analysis_file),
|
|
'--format', 'json',
|
|
'--output', str(output_file)
|
|
])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert output_file.exists()
|
|
|
|
# Verify JSON content
|
|
with open(output_file, 'r') as f:
|
|
data = json.load(f)
|
|
|
|
assert data['metadata']['series_count'] == 1
|
|
assert len(data['series']) == 1
|
|
assert data['series'][0]['title'] == 'The Wire'
|
|
|
|
def test_report_duplicates_text(self, tmp_path):
|
|
"""Test duplicate report generation in text format."""
|
|
# Create test analysis JSON
|
|
analysis_file = tmp_path / "analysis.json"
|
|
analysis_data = {
|
|
"metadata": {},
|
|
"completeness": [],
|
|
"duplicates": [
|
|
{
|
|
"identity": {
|
|
"type": "movie",
|
|
"title": "The Matrix",
|
|
"year": 1999
|
|
},
|
|
"files": [
|
|
"/movies/The.Matrix.1999.1080p.mkv",
|
|
"/movies/The.Matrix.1999.720p.mkv"
|
|
],
|
|
"quality_comparison": [
|
|
{
|
|
"filename": "The.Matrix.1999.1080p.mkv",
|
|
"path": "/movies/The.Matrix.1999.1080p.mkv",
|
|
"size_bytes": 2000000000,
|
|
"resolution": "1920x1080"
|
|
},
|
|
{
|
|
"filename": "The.Matrix.1999.720p.mkv",
|
|
"path": "/movies/The.Matrix.1999.720p.mkv",
|
|
"size_bytes": 1000000000,
|
|
"resolution": "1280x720"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
|
|
with open(analysis_file, 'w') as f:
|
|
json.dump(analysis_data, f)
|
|
|
|
# Run command
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'duplicates',
|
|
'--input', str(analysis_file),
|
|
'--format', 'text'
|
|
])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert "Loaded 1 duplicate groups" in result.output
|
|
assert "The Matrix (1999)" in result.output
|
|
assert "1920x1080" in result.output
|
|
|
|
def test_report_duplicates_json(self, tmp_path):
|
|
"""Test duplicate report generation in JSON format."""
|
|
# Create test analysis JSON
|
|
analysis_file = tmp_path / "analysis.json"
|
|
analysis_data = {
|
|
"metadata": {},
|
|
"completeness": [],
|
|
"duplicates": [
|
|
{
|
|
"identity": {
|
|
"type": "series",
|
|
"title": "Breaking Bad",
|
|
"season": 1,
|
|
"episodes": [1]
|
|
},
|
|
"files": [
|
|
"/series/Breaking.Bad.S01E01.1080p.mkv",
|
|
"/series/Breaking.Bad.S01E01.720p.mkv"
|
|
],
|
|
"quality_comparison": [
|
|
{
|
|
"filename": "Breaking.Bad.S01E01.1080p.mkv",
|
|
"path": "/series/Breaking.Bad.S01E01.1080p.mkv",
|
|
"size_bytes": 1500000000
|
|
},
|
|
{
|
|
"filename": "Breaking.Bad.S01E01.720p.mkv",
|
|
"path": "/series/Breaking.Bad.S01E01.720p.mkv",
|
|
"size_bytes": 800000000
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
|
|
with open(analysis_file, 'w') as f:
|
|
json.dump(analysis_data, f)
|
|
|
|
# Run command with output file
|
|
output_file = tmp_path / "duplicates_report.json"
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'duplicates',
|
|
'--input', str(analysis_file),
|
|
'--format', 'json',
|
|
'--output', str(output_file)
|
|
])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert output_file.exists()
|
|
|
|
# Verify JSON content
|
|
with open(output_file, 'r') as f:
|
|
data = json.load(f)
|
|
|
|
assert data['metadata']['duplicate_groups'] == 1
|
|
assert len(data['duplicates']) == 1
|
|
|
|
def test_report_summary(self, tmp_path):
|
|
"""Test summary report generation."""
|
|
# Create test inventory CSV
|
|
inventory_file = tmp_path / "inventory.csv"
|
|
with open(inventory_file, 'w', encoding='utf-8') as f:
|
|
f.write("# Generated: 2024-01-01T00:00:00\n")
|
|
f.write("# Library Root: /test/library\n")
|
|
f.write("path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n")
|
|
f.write("/test/library/movie/Movie1.mkv,Movie1.mkv,2000000000,2024-01-01T00:00:00,movie,,,\n")
|
|
f.write("/test/library/movie/Movie2.mkv,Movie2.mkv,1500000000,2024-01-01T00:00:00,movie,,,\n")
|
|
f.write("/test/library/series/Show.S01E01.mkv,Show.S01E01.mkv,1000000000,2024-01-01T00:00:00,series,,,\n")
|
|
f.write("/test/library/anime/Anime1.mkv,Anime1.mkv,800000000,2024-01-01T00:00:00,anime,,,\n")
|
|
|
|
# Run command
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'summary',
|
|
'--input', str(inventory_file)
|
|
])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert "Loaded 4 files" in result.output
|
|
assert "Total Files: 4" in result.output
|
|
assert "Movie:" in result.output
|
|
assert "Series:" in result.output
|
|
assert "Anime:" in result.output
|
|
|
|
def test_report_summary_with_output_file(self, tmp_path):
|
|
"""Test summary report generation with output file."""
|
|
# Create test inventory CSV
|
|
inventory_file = tmp_path / "inventory.csv"
|
|
with open(inventory_file, 'w', encoding='utf-8') as f:
|
|
f.write("# Generated: 2024-01-01T00:00:00\n")
|
|
f.write("# Library Root: /test/library\n")
|
|
f.write("path,filename,size_bytes,modified_timestamp,category,resolution,codec,duration_seconds,bitrate_kbps\n")
|
|
f.write("/test/library/movie/Movie1.mkv,Movie1.mkv,1000000,2024-01-01T00:00:00,movie,,,\n")
|
|
|
|
# Run command with output file
|
|
output_file = tmp_path / "summary_report.txt"
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'summary',
|
|
'--input', str(inventory_file),
|
|
'--output', str(output_file)
|
|
])
|
|
|
|
# Verify success
|
|
assert result.exit_code == 0
|
|
assert output_file.exists()
|
|
|
|
# Verify file content
|
|
with open(output_file, 'r') as f:
|
|
content = f.read()
|
|
|
|
assert "Total Files: 1" in content
|
|
assert "Movie:" in content
|
|
|
|
def test_report_inventory_missing_file(self, tmp_path):
|
|
"""Test inventory report with missing input file."""
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'inventory',
|
|
'--input', str(tmp_path / "nonexistent.csv")
|
|
])
|
|
|
|
# Verify runtime missing-file handling
|
|
assert result.exit_code != 0
|
|
assert "Error: Input file not found:" in result.output
|
|
|
|
def test_report_completeness_missing_file(self, tmp_path):
|
|
"""Test completeness report with missing input file."""
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, [
|
|
'report', 'completeness',
|
|
'--input', str(tmp_path / "nonexistent.json")
|
|
])
|
|
|
|
# Verify runtime missing-file handling
|
|
assert result.exit_code != 0
|
|
assert "Error: Input file not found:" in result.output
|