from types import SimpleNamespace from wordarr.importer.matcher import best_matches, normalize, score def req(id, title, authors="", media_type="ebook"): return SimpleNamespace(id=id, title=title, authors=authors, media_type=media_type, volume=None) def test_normalize(): assert normalize("J.R.R._Tolkien-The_Hobbit[retail].epub") == "j r r tolkien the hobbit" def test_match_finds_right_request(): requests = [ req(1, "The Hobbit", "J.R.R. Tolkien"), req(2, "Dune", "Frank Herbert"), ] items = [{"path": "/d/x.epub", "name": "Frank Herbert - Dune (1965) retail", "media_type": "ebook", "is_dir": False, "files": ["/d/x.epub"]}] out = best_matches(items, requests) assert out[0]["suggested_request_id"] == 2 def test_no_match_for_unrelated_file(): requests = [req(1, "The Hobbit", "Tolkien")] items = [{"path": "/d/y.epub", "name": "Cooking for Dummies 2019", "media_type": "ebook", "is_dir": False, "files": ["/d/y.epub"]}] out = best_matches(items, requests) assert out[0]["suggested_request_id"] is None def test_media_type_filter(): requests = [req(1, "Dune", "Herbert", media_type="audiobook")] items = [{"path": "/d/dune.epub", "name": "Herbert - Dune", "media_type": "ebook", "is_dir": False, "files": ["/d/dune.epub"]}] out = best_matches(items, requests) assert out[0]["suggested_request_id"] is None def test_volume_number_must_match(): r1 = req(1, "Die drei ??? Folge 001", "", media_type="audiobook") r1.volume = 1 r123 = req(2, "Die drei ??? Folge 123", "", media_type="audiobook") r123.volume = 123 items = [{"path": "/d/f.mp3", "name": "Die drei Fragezeichen - Folge 123 - Der Superpapagei", "media_type": "audiobook", "is_dir": False, "files": ["/d/f.mp3"]}] out = best_matches(items, [r1, r123]) assert out[0]["suggested_request_id"] == 2 def test_leetspeak_title_matches(): assert normalize("DiE DR3i - Folge 03") == "die drei folge 03" # digits at a word edge stay put, they carry the episode number assert normalize("Folge03 v2 [m4b]") == "folge03" r = req(1, "Die dr3i - Böses Erwachen", media_type="audiobook") r.volume = 2 items = [{"path": "/d/x", "name": "Die drei 02 - Boeses Erwachen", "media_type": "audiobook", "is_dir": True, "files": ["/d/x/a.mp3"]}] out = best_matches(items, [r]) assert out[0]["suggested_request_id"] == 1 def test_digit_inside_word_is_not_a_volume(): from wordarr.importer.matcher import score r = req(1, "Die dr3i - Folge 5", media_type="audiobook") r.volume = 5 # "dr3i" must not contribute a "3" that satisfies the volume check r3 = req(2, "Die dr3i - Folge 3", media_type="audiobook") r3.volume = 3 assert score("DiE DR3i - 05 - Der Fall", r) > score("DiE DR3i - 05 - Der Fall", r3) def test_series_in_folder_path_carries_the_match(): """Downloads named "001 - Titel" only match via the series in their path.""" r = req(1, "Die drei ??? Folge 001", media_type="audiobook") r.volume, r.series = 1, "Die drei ???" item = {"path": "/d/x", "name": "001 - Der Super - Papagei", "rel_dir": "Die Drei Fragezeichen/Folgen/3478632869 001-010", "media_type": "audiobook", "is_dir": True, "files": ["/d/x/a.mp3"]} out = best_matches([item], [r]) assert out[0]["suggested_request_id"] == 1 assert out[0]["score"] >= 90 # without the series context it stays a weak fuzzy guess assert score("001 - Der Super - Papagei", r) < 90 def test_questionmarks_equal_fragezeichen(): assert normalize("Die drei ???") == normalize("Die Drei Fragezeichen") def test_disc_count_is_not_an_episode_number(): r = req(1, "Die drei ??? und der Phantomsee", media_type="audiobook") r.volume = 2 # "(2 CDs)" must not satisfy the volume check of episode 2 assert score("Die drei Fragezeichen 001 - Super-Papagei (2 CDs)", r) == 40.0