diff --git a/AGENTS.md b/AGENTS.md index 8cb5025..e39bafc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,7 +48,7 @@ bdpl/ │ ├── test_ig_stream.py # IG stream parser tests (ICS fixture) │ ├── test_ordering.py # Episode ordering unit tests │ ├── test_disc1_scan.py # disc1 integration tests -│ ├── test_disc2_scan.py # disc2 chapter-splitting tests +│ ├── test_disc14_scan.py # disc14 chapter-splitting tests │ ├── test_disc3_scan.py # disc3 integration tests │ ├── test_disc4_scan.py # disc4 single-main-title + archive tests │ ├── test_disc5_scan.py # disc5 visible/hidden specials tests @@ -122,7 +122,7 @@ bdpl archive /path/to/BDMV --out ./DigitalArchive pytest tests/ -v ``` -Tests use bundled fixture data from `tests/fixtures/disc1/` and `tests/fixtures/disc2/` by default. Set `BDPL_TEST_BDMV` to override with a real BDMV directory. +Tests use bundled fixture data from `tests/fixtures/disc1/` and `tests/fixtures/disc14/` by default. Set `BDPL_TEST_BDMV` to override with a real BDMV directory. ```bash # Run all tests (unit tests always run; integration tests need a BDMV) diff --git a/PLAN.md b/PLAN.md index 5ed2ca9..247b5c8 100644 --- a/PLAN.md +++ b/PLAN.md @@ -470,7 +470,7 @@ Files implemented: - `tests/` — 131 tests (reader, mpls, clpi, index, movieobject, ig_stream, ordering, scan, disc-specific integration, matrix, fixture integrity, visibility heuristics, visible-only export, CLI, digital archive) - `tests/builders.py` — Shared test-data builders for model objects - `tests/fixtures/disc1/` — Bundled MPLS/CLPI/index/MovieObject from multi-episode disc -- `tests/fixtures/disc2/` — Bundled metadata + ICS fixture from single-m2ts chapter-split disc +- `tests/fixtures/disc14/` — Bundled metadata + ICS fixture from single-m2ts chapter-split disc - `tests/fixtures/disc3/` — Bundled metadata fixture with 4 inferred episodes - `tests/fixtures/disc4/` — Bundled metadata fixture for single 44:03 main title + digital archive menu gallery - `tests/fixtures/disc5/` — Bundled metadata fixture for visible/hidden specials behavior diff --git a/tests/conftest.py b/tests/conftest.py index 85c5bcb..2d373dd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -59,9 +59,9 @@ def disc1_path() -> Path: @pytest.fixture(scope="session") -def disc2_path() -> Path: - """Return path to bundled disc2 fixture.""" - return _fixture_path("disc2") +def disc14_path() -> Path: + """Return path to bundled disc14 fixture.""" + return _fixture_path("disc14") @pytest.fixture(scope="session") @@ -95,9 +95,9 @@ def disc1_analysis(disc1_path): @pytest.fixture(scope="session") -def disc2_analysis(disc2_path): - """Run and cache full analysis for bundled disc2 fixture.""" - return _analyze_fixture(disc2_path) +def disc14_analysis(disc14_path): + """Run and cache full analysis for bundled disc14 fixture.""" + return _analyze_fixture(disc14_path) @pytest.fixture(scope="session") diff --git a/tests/fixtures/disc2/CLIPINF/00000.clpi b/tests/fixtures/disc14/CLIPINF/00000.clpi similarity index 100% rename from tests/fixtures/disc2/CLIPINF/00000.clpi rename to tests/fixtures/disc14/CLIPINF/00000.clpi diff --git a/tests/fixtures/disc2/CLIPINF/00001.clpi b/tests/fixtures/disc14/CLIPINF/00001.clpi similarity index 100% rename from tests/fixtures/disc2/CLIPINF/00001.clpi rename to tests/fixtures/disc14/CLIPINF/00001.clpi diff --git a/tests/fixtures/disc2/CLIPINF/00002.clpi b/tests/fixtures/disc14/CLIPINF/00002.clpi similarity index 100% rename from tests/fixtures/disc2/CLIPINF/00002.clpi rename to tests/fixtures/disc14/CLIPINF/00002.clpi diff --git a/tests/fixtures/disc2/CLIPINF/00003.clpi b/tests/fixtures/disc14/CLIPINF/00003.clpi similarity index 100% rename from tests/fixtures/disc2/CLIPINF/00003.clpi rename to tests/fixtures/disc14/CLIPINF/00003.clpi diff --git a/tests/fixtures/disc2/CLIPINF/00004.clpi b/tests/fixtures/disc14/CLIPINF/00004.clpi similarity index 100% rename from tests/fixtures/disc2/CLIPINF/00004.clpi rename to tests/fixtures/disc14/CLIPINF/00004.clpi diff --git a/tests/fixtures/disc2/CLIPINF/00006.clpi b/tests/fixtures/disc14/CLIPINF/00006.clpi similarity index 100% rename from tests/fixtures/disc2/CLIPINF/00006.clpi rename to tests/fixtures/disc14/CLIPINF/00006.clpi diff --git a/tests/fixtures/disc2/CLIPINF/00007.clpi b/tests/fixtures/disc14/CLIPINF/00007.clpi similarity index 100% rename from tests/fixtures/disc2/CLIPINF/00007.clpi rename to tests/fixtures/disc14/CLIPINF/00007.clpi diff --git a/tests/fixtures/disc2/META/DL/bdmt_eng.xml b/tests/fixtures/disc14/META/DL/bdmt_eng.xml similarity index 83% rename from tests/fixtures/disc2/META/DL/bdmt_eng.xml rename to tests/fixtures/disc14/META/DL/bdmt_eng.xml index 8b24ea1..98b388c 100644 --- a/tests/fixtures/disc2/META/DL/bdmt_eng.xml +++ b/tests/fixtures/disc14/META/DL/bdmt_eng.xml @@ -3,7 +3,7 @@ xmlns:di="urn:BDA:bdmv;discinfo"> - TEST DISC 2 + TEST DISC 14 diff --git a/tests/fixtures/disc2/MovieObject.bdmv b/tests/fixtures/disc14/MovieObject.bdmv similarity index 100% rename from tests/fixtures/disc2/MovieObject.bdmv rename to tests/fixtures/disc14/MovieObject.bdmv diff --git a/tests/fixtures/disc2/PLAYLIST/00000.mpls b/tests/fixtures/disc14/PLAYLIST/00000.mpls similarity index 100% rename from tests/fixtures/disc2/PLAYLIST/00000.mpls rename to tests/fixtures/disc14/PLAYLIST/00000.mpls diff --git a/tests/fixtures/disc2/PLAYLIST/00001.mpls b/tests/fixtures/disc14/PLAYLIST/00001.mpls similarity index 100% rename from tests/fixtures/disc2/PLAYLIST/00001.mpls rename to tests/fixtures/disc14/PLAYLIST/00001.mpls diff --git a/tests/fixtures/disc2/PLAYLIST/00002.mpls b/tests/fixtures/disc14/PLAYLIST/00002.mpls similarity index 100% rename from tests/fixtures/disc2/PLAYLIST/00002.mpls rename to tests/fixtures/disc14/PLAYLIST/00002.mpls diff --git a/tests/fixtures/disc2/ics_menu.bin b/tests/fixtures/disc14/ics_menu.bin similarity index 100% rename from tests/fixtures/disc2/ics_menu.bin rename to tests/fixtures/disc14/ics_menu.bin diff --git a/tests/fixtures/disc2/index.bdmv b/tests/fixtures/disc14/index.bdmv similarity index 100% rename from tests/fixtures/disc2/index.bdmv rename to tests/fixtures/disc14/index.bdmv diff --git a/tests/test_disc2_scan.py b/tests/test_disc14_scan.py similarity index 50% rename from tests/test_disc2_scan.py rename to tests/test_disc14_scan.py index ee42283..23ad6f3 100644 --- a/tests/test_disc2_scan.py +++ b/tests/test_disc14_scan.py @@ -1,4 +1,4 @@ -"""Tests for chapter-based episode splitting (disc2 fixture).""" +"""Tests for chapter-based episode splitting (disc14 fixture).""" import pytest @@ -8,23 +8,23 @@ class TestChapterSplitting: - def test_finds_four_episodes(self, disc2_analysis: DiscAnalysis) -> None: - da = disc2_analysis + def test_finds_four_episodes(self, disc14_analysis: DiscAnalysis) -> None: + da = disc14_analysis assert len(da.episodes) == 4 - def test_episode_durations_reasonable(self, disc2_analysis: DiscAnalysis) -> None: - da = disc2_analysis + def test_episode_durations_reasonable(self, disc14_analysis: DiscAnalysis) -> None: + da = disc14_analysis for ep in da.episodes: dur_min = ep.duration_ms / 60000 assert 15 < dur_min < 35, f"Ep {ep.episode} duration {dur_min:.1f}min out of range" - def test_episodes_are_ordered(self, disc2_analysis: DiscAnalysis) -> None: - da = disc2_analysis + def test_episodes_are_ordered(self, disc14_analysis: DiscAnalysis) -> None: + da = disc14_analysis nums = [ep.episode for ep in da.episodes] assert nums == [1, 2, 3, 4] - def test_episode_segments_dont_overlap(self, disc2_analysis: DiscAnalysis) -> None: - da = disc2_analysis + def test_episode_segments_dont_overlap(self, disc14_analysis: DiscAnalysis) -> None: + da = disc14_analysis for i in range(len(da.episodes) - 1): seg_a = da.episodes[i].segments[0] seg_b = da.episodes[i + 1].segments[0] @@ -32,10 +32,10 @@ def test_episode_segments_dont_overlap(self, disc2_analysis: DiscAnalysis) -> No f"Ep {i + 1} end {seg_a.out_ms} overlaps Ep {i + 2} start {seg_b.in_ms}" ) - def test_no_special_features(self, disc2_analysis: DiscAnalysis) -> None: - """Disc2 is a chapter-split disc with no extras.""" - assert len(disc2_analysis.special_features) == 0 + def test_no_special_features(self, disc14_analysis: DiscAnalysis) -> None: + """Disc14 is a chapter-split disc with no extras.""" + assert len(disc14_analysis.special_features) == 0 - def test_disc_title(self, disc2_analysis: DiscAnalysis) -> None: + def test_disc_title(self, disc14_analysis: DiscAnalysis) -> None: """Disc title should be extracted from META/DL/bdmt_eng.xml.""" - assert disc2_analysis.disc_title == "TEST DISC 2" + assert disc14_analysis.disc_title == "TEST DISC 14" diff --git a/tests/test_disc_matrix.py b/tests/test_disc_matrix.py index af7cffc..4ee585c 100644 --- a/tests/test_disc_matrix.py +++ b/tests/test_disc_matrix.py @@ -13,7 +13,7 @@ ("analysis_fixture", "expected_episode_count", "expected_episode_playlists"), [ ("disc1_analysis", 3, ["00002.mpls", "00002.mpls", "00002.mpls"]), - ("disc2_analysis", 4, ["00002.mpls", "00002.mpls", "00002.mpls", "00002.mpls"]), + ("disc14_analysis", 4, ["00002.mpls", "00002.mpls", "00002.mpls", "00002.mpls"]), ("disc3_analysis", 4, ["00002.mpls", "00002.mpls", "00002.mpls", "00002.mpls"]), ("disc4_analysis", 1, ["00002.mpls"]), ("disc5_analysis", 1, ["00001.mpls"]), @@ -44,7 +44,7 @@ def test_disc_episode_expectation_matrix( ("analysis_fixture", "expected_total", "expected_visible"), [ # (analysis_fixture, expected_total, expected_visible) ("disc1_analysis", 9, 9), # 7 title-hint + 2 chapter-split - ("disc2_analysis", 0, 0), # chapter-split disc with no extras + ("disc14_analysis", 0, 0), # chapter-split disc with no extras ("disc3_analysis", 0, 0), # chapter-split disc with no extras ("disc5_analysis", 14, 11), # 14 IG-derived, 11 visible content buttons ("disc6_analysis", 3, 3), # 3 title-hint specials @@ -77,7 +77,7 @@ def test_disc_special_visibility_expectation_matrix( "analysis_fixture", [ "disc1_analysis", - "disc2_analysis", + "disc14_analysis", "disc3_analysis", "disc4_analysis", "disc5_analysis", @@ -115,7 +115,7 @@ def test_disc_episode_segment_boundaries_matrix( "analysis_fixture", [ "disc1_analysis", - "disc2_analysis", + "disc14_analysis", "disc3_analysis", "disc4_analysis", "disc5_analysis", @@ -160,7 +160,7 @@ def test_disc_special_boundary_semantics_matrix( ("analysis_fixture", "expected_chapter_split_specials"), [ # (analysis_fixture, expected_chapter_split_specials) ("disc1_analysis", 2), # PlayPL_PM marks → 2 chapter-split entries - ("disc2_analysis", 0), + ("disc14_analysis", 0), ("disc3_analysis", 0), ("disc4_analysis", 0), ("disc5_analysis", 0), @@ -191,7 +191,7 @@ def test_disc_special_chapter_split_expectation_matrix( @pytest.mark.parametrize( ("analysis_fixture", "expected_title"), [ - ("disc2_analysis", "TEST DISC 2"), + ("disc14_analysis", "TEST DISC 14"), ("disc6_analysis", "TEST DISC 6"), ("disc7_analysis", "TEST DISC 7 VOL 2"), ("disc8_analysis", "TEST DISC 8"), diff --git a/tests/test_ig_stream.py b/tests/test_ig_stream.py index b2449a7..03d331b 100644 --- a/tests/test_ig_stream.py +++ b/tests/test_ig_stream.py @@ -12,13 +12,13 @@ parse_ics, ) -_FIXTURE_DIR: Path = Path(__file__).parent / "fixtures" / "disc2" +_FIXTURE_DIR: Path = Path(__file__).parent / "fixtures" / "disc14" _ICS_FILE: Path = _FIXTURE_DIR / "ics_menu.bin" @pytest.fixture() def ics() -> InteractiveComposition: - """Parse the disc2 ICS fixture.""" + """Parse the disc14 ICS fixture.""" data: bytes = _ICS_FILE.read_bytes() return parse_ics(data) @@ -35,7 +35,7 @@ def test_ics_dimensions(ics: InteractiveComposition) -> None: def test_ics_page_count(ics: InteractiveComposition) -> None: - """Disc2 menu has 4 pages.""" + """Disc14 menu has 4 pages.""" assert len(ics.pages) == 4 @@ -64,14 +64,14 @@ def test_extract_hints_returns_actions(ics: InteractiveComposition) -> None: def test_hints_contain_register_sets(ics: InteractiveComposition) -> None: - """Disc2 episode buttons should SET GPR registers.""" + """Disc14 episode buttons should SET GPR registers.""" hints: list[IGMenuHint] = extract_menu_hints(ics) reg_hints: list[IGMenuHint] = [h for h in hints if h.register_sets] assert len(reg_hints) > 0, "Expected some register-setting buttons" def test_hints_episode_register_pattern(ics: InteractiveComposition) -> None: - """Disc2 episode selection buttons SET reg6 to episode indices 0-5.""" + """Disc14 episode selection buttons SET reg6 to episode indices 0-5.""" hints: list[IGMenuHint] = extract_menu_hints(ics) reg6_values: list[int] = sorted(set(h.register_sets[6] for h in hints if 6 in h.register_sets)) # reg6 values 0-5 map to episode/segment selection @@ -80,7 +80,7 @@ def test_hints_episode_register_pattern(ics: InteractiveComposition) -> None: def test_episode_chapter_pattern(ics: InteractiveComposition) -> None: - """Disc2 has buttons that SET reg2 to chapter-mark multiples of 5. + """Disc14 has buttons that SET reg2 to chapter-mark multiples of 5. This confirms the 5-chapters-per-episode pattern (marks 0, 5, 10, 15). """