"""Tests for the I/O layer module.""" import json from datetime import datetime, timezone from pathlib import Path import pytest from vlm.io import ( _video_file_from_record, load_identities_json, save_identities_json, ) from vlm.models import VideoFile class TestVideoFileFromRecord: """Tests for _video_file_from_record function.""" def test_video_file_from_record_with_metadata_v2(self): """Test loading VideoFile from v2 record with embedded metadata.""" record = { "path": "/library/movie/The Matrix (1999).mkv", "filename": "The Matrix (1999).mkv", "category": "movie", "title": "The Matrix", "year": 1999, "confidence": 0.9, "needs_review": False, "video_metadata": { "size_bytes": 1234567890, "modified_timestamp": "2024-01-01T10:00:00+00:00", "resolution": "1920x1080", "codec": "h264", "duration_seconds": 7200.5, "bitrate_kbps": 5000, }, } vf = _video_file_from_record(record) assert vf.path == Path("/library/movie/The Matrix (1999).mkv") assert vf.filename == "The Matrix (1999).mkv" assert vf.category == "movie" assert vf.size_bytes == 1234567890 assert vf.resolution == "1920x1080" assert vf.codec == "h264" assert vf.duration_seconds == 7200.5 assert vf.bitrate_kbps == 5000 assert isinstance(vf.modified_timestamp, datetime) def test_video_file_from_record_without_metadata_v1(self): """Test loading VideoFile from v1 record without metadata (backward compatibility).""" record = { "path": "/library/movie/Inception (2010).mkv", "filename": "Inception (2010).mkv", "category": "movie", "title": "Inception", "year": 2010, "confidence": 0.9, "needs_review": False, } vf = _video_file_from_record(record) assert vf.path == Path("/library/movie/Inception (2010).mkv") assert vf.filename == "Inception (2010).mkv" assert vf.category == "movie" # v1 defaults assert vf.size_bytes == 0 assert vf.resolution is None assert vf.codec is None assert vf.duration_seconds is None assert vf.bitrate_kbps is None assert isinstance(vf.modified_timestamp, datetime) def test_video_file_from_record_partial_metadata(self): """Test loading VideoFile with partial metadata (some fields missing).""" record = { "path": "/library/series/Breaking Bad S01E01.mkv", "filename": "Breaking Bad S01E01.mkv", "category": "series", "title": "Breaking Bad", "season": 1, "episodes": [1], "confidence": 0.9, "needs_review": False, "video_metadata": { "size_bytes": 987654321, "modified_timestamp": "2024-02-01T15:30:00+00:00", "resolution": "1280x720", # codec missing # duration_seconds missing # bitrate_kbps missing }, } vf = _video_file_from_record(record) assert vf.size_bytes == 987654321 assert vf.resolution == "1280x720" assert vf.codec is None assert vf.duration_seconds is None assert vf.bitrate_kbps is None class TestIdentitiesJsonVersioning: """Tests for identities.json schema versioning.""" def test_load_identities_v2_with_metadata(self, tmp_path): """Test loading v2 identities.json with video metadata.""" identities_file = tmp_path / "identities.json" data = { "vlm_schema_version": "2.0", "metadata": { "generated": "2024-01-01T10:00:00", "source_inventory": "inventory.csv", "total_files": 1, }, "movies": [ { "path": "/library/movie/Test (2024).mkv", "filename": "Test (2024).mkv", "category": "movie", "title": "Test", "year": 2024, "confidence": 0.9, "needs_review": False, "video_metadata": { "size_bytes": 1000000, "modified_timestamp": "2024-01-01T00:00:00+00:00", "resolution": "1920x1080", "codec": "h264", "duration_seconds": 3600.0, "bitrate_kbps": 2500, }, } ], "series": [], "anime": [], "other": [], } save_identities_json(data, identities_file) loaded = load_identities_json(identities_file) assert loaded["vlm_schema_version"] == "2.0" assert len(loaded["movies"]) == 1 assert "video_metadata" in loaded["movies"][0] assert loaded["movies"][0]["video_metadata"]["size_bytes"] == 1000000 def test_load_identities_v1_backward_compatibility(self, tmp_path): """Test loading v1 identities.json without version field (backward compatibility).""" identities_file = tmp_path / "identities.json" data = { # No vlm_schema_version field (v1) "metadata": { "generated": "2024-01-01T10:00:00", "source_inventory": "inventory.csv", "total_files": 1, }, "movies": [ { "path": "/library/movie/Old (2023).mkv", "filename": "Old (2023).mkv", "category": "movie", "title": "Old", "year": 2023, "confidence": 0.9, "needs_review": False, # No video_metadata field } ], "series": [], "anime": [], "other": [], } save_identities_json(data, identities_file) loaded = load_identities_json(identities_file) # v1 files don't have version field assert "vlm_schema_version" not in loaded or loaded.get("vlm_schema_version") is None assert len(loaded["movies"]) == 1 assert "video_metadata" not in loaded["movies"][0] class TestIdentitiesJsonRoundTrip: """Tests for identities.json save/load round-trip.""" def test_save_and_load_v2_identities(self, tmp_path): """Test saving and loading v2 identities with metadata.""" identities_file = tmp_path / "identities_v2.json" original_data = { "vlm_schema_version": "2.0", "metadata": { "generated": "2024-02-13T12:00:00", "source_inventory": "test_inventory.csv", "total_files": 2, }, "movies": [ { "path": "/library/movie/Movie1 (2024).mkv", "filename": "Movie1 (2024).mkv", "category": "movie", "title": "Movie1", "year": 2024, "confidence": 0.9, "needs_review": False, "video_metadata": { "size_bytes": 2000000000, "modified_timestamp": "2024-02-10T08:00:00+00:00", "resolution": "3840x2160", "codec": "hevc", "duration_seconds": 7200.0, "bitrate_kbps": 8000, }, } ], "series": [ { "path": "/library/series/Show S01E01.mkv", "filename": "Show S01E01.mkv", "category": "series", "title": "Show", "season": 1, "episodes": [1], "confidence": 0.9, "needs_review": False, "video_metadata": { "size_bytes": 500000000, "modified_timestamp": "2024-02-11T10:00:00+00:00", "resolution": "1920x1080", "codec": "h264", "duration_seconds": 2700.0, "bitrate_kbps": 3000, }, } ], "anime": [], "other": [], } save_identities_json(original_data, identities_file) loaded_data = load_identities_json(identities_file) # Verify structure assert loaded_data["vlm_schema_version"] == "2.0" assert len(loaded_data["movies"]) == 1 assert len(loaded_data["series"]) == 1 # Verify movie metadata preserved movie = loaded_data["movies"][0] assert movie["video_metadata"]["size_bytes"] == 2000000000 assert movie["video_metadata"]["resolution"] == "3840x2160" assert movie["video_metadata"]["codec"] == "hevc" # Verify series metadata preserved series = loaded_data["series"][0] assert series["video_metadata"]["size_bytes"] == 500000000 assert series["video_metadata"]["resolution"] == "1920x1080" assert series["video_metadata"]["codec"] == "h264"