""" Tests for indexer/title_parse.py — synthetic filenames only, one per docs/mediacenter.md §3.3/§3.4 rule. The real ~1950-file library validation is a manual acceptance step (§11), not something this repo's corpus holds. """ from meshbay_node.indexer.title_parse import ( ParsedName, naive_title, parse_episode_filename, parse_movie_filename, season_from_folder_name, sequel_variants, ) # ── §3.3 row: plain, well-formed movie filename ────────────────────────────── def test_plain_movie_filename_parses_confidently(): r = parse_movie_filename("The.Great.Adventure.2015.1080p.BluRay.x264.mkv") assert r.display_title == "The Great Adventure" assert r.year == 2015 assert r.confidence is True # ── §3.3 row 1: real title in alternative_title ────────────────────────────── def test_franchise_numeric_code_exposes_alternative_title(): r = parse_movie_filename("Franchise.007.-.The.Real.Subtitle.1999.720p.mkv") assert r.year == 1999 # guessit lands the franchise fragment in title and the real subtitle in # alternative_title — both must be surfaced so a caller (tmdb.py) can # try either, per the design doc's "search both fields" fix. assert r.alt_title is not None # ── §3.3 row 2: hyphenated title split before a parenthesized year ─────────── def test_naive_title_normalizes_hyphens_dots_and_underscores(): nt = naive_title("Hero-Name.(2002).DVDRip.XviD-GROUP.avi") assert "-" not in nt assert "." not in nt assert "_" not in nt assert "2002" not in nt # the year itself is stripped, not just its parens assert "Hero" in nt and "Name" in nt # ── §3.3 row 3: French edition vocabulary stuck to the title ───────────────── def test_french_edition_phrases_are_stripped(): r = parse_movie_filename("Some.Movie.Version.Longue.2010.mkv") assert "version" not in (r.display_title or "").lower() assert "longue" not in (r.display_title or "").lower() r2 = parse_movie_filename("Autre.Film.Remasterise.1998.mkv") assert "remasteris" not in (r2.display_title or "").lower() # ── §3.3 row 4: trailing sequel digit / Roman numeral ──────────────────────── def test_sequel_variants_strips_digit_and_offers_roman_numeral(): variants = sequel_variants("Some Sequel 2") assert "Some Sequel" in variants assert "Some Sequel II" in variants def test_sequel_variants_empty_when_no_trailing_digit(): assert sequel_variants("Some Movie") == [] # ── §3.3 row 6: no usable title at all ─────────────────────────────────────── def test_low_confidence_when_no_title_or_year(): r = parse_movie_filename("abc123.mkv") assert r.confidence is False # the mandated fallback is always available regardless assert r.naive_title == "abc123" # ── §3.2/§3.4: episode filename with no show name at all ───────────────────── def test_episode_only_filename_has_no_title_but_has_season_episode(): r = parse_episode_filename("S08E02.SUBFRENCH.720p.mkv") assert r.display_title is None assert r.season == 8 assert r.episode == 2 # confidence is False (no title yet) — the indexer must supply one from # a representative sibling filename in the same folder, per §3.4. assert r.confidence is False def test_episode_filename_with_show_name_parses_confidently(): r = parse_episode_filename("Some.Show.Name.S02E05.720p.WEB.mkv") assert r.display_title == "Some Show Name" assert r.season == 2 assert r.episode == 5 assert r.confidence is True # ── §3.4: season-like ancestor folders, including non-English vocabulary ──── def test_season_folder_english(): assert season_from_folder_name("Season 2") == 2 def test_season_folder_french_word(): assert season_from_folder_name("Saison 3") == 3 def test_season_folder_roman_numeral(): assert season_from_folder_name("Saison IV") == 4 def test_season_folder_book_word_roman_numeral(): # Some shows number their seasons by "book" (Roman numerals) rather # than "season"/"saison" — real, observed vocabulary (§3.4). assert season_from_folder_name("Livre I") == 1 assert season_from_folder_name("Livre VI") == 6 def test_specials_folder_maps_to_season_zero(): assert season_from_folder_name("Specials") == 0 assert season_from_folder_name("Bonus") == 0 assert season_from_folder_name("Extras") == 0 def test_non_season_folder_name_returns_none(): assert season_from_folder_name("Some Show Name") is None def test_parsed_name_is_a_plain_dataclass(): # sanity: constructible with just the one required field, per the # "None => caller must supply from elsewhere" contract. p = ParsedName(display_title=None) assert p.confidence is False assert p.naive_title == ""