# -*- coding: utf-8 -*- """ Tests fuer den ChannelMapper und die CHANNELS-Definitionen. Testet Alias-Aufloesung, XMLTV-Mapping, Sender-Filterung und benutzerdefinierte Aliase. """ from __future__ import annotations import pytest from plugins.tv_program.epg.channels import CHANNELS, ChannelMapper # ============================================================================ # CHANNELS-Dict Struktur # ============================================================================ class TestChannelsDictStruktur: """Tests fuer die CHANNELS-Konstantendefinition.""" def test_channels_enthaelt_ard(self) -> None: """ARD muss im CHANNELS-Dict vorhanden sein.""" assert "ard" in CHANNELS def test_channels_enthaelt_zdf(self) -> None: """ZDF muss im CHANNELS-Dict vorhanden sein.""" assert "zdf" in CHANNELS def test_channels_enthaelt_rtl(self) -> None: """RTL muss im CHANNELS-Dict vorhanden sein.""" assert "rtl" in CHANNELS def test_channels_enthaelt_sat1(self) -> None: """SAT.1 muss im CHANNELS-Dict vorhanden sein.""" assert "sat1" in CHANNELS def test_channels_enthaelt_pro7(self) -> None: """ProSieben muss im CHANNELS-Dict vorhanden sein.""" assert "pro7" in CHANNELS def test_channels_enthaelt_mindestens_35_sender(self) -> None: """Das CHANNELS-Dict muss mindestens 35 Sender enthalten.""" assert len(CHANNELS) >= 35 def test_channels_eintraege_haben_pflichtfelder(self) -> None: """Jeder Sender muss name, aliases, group und xmltv_ids haben.""" for channel_id, info in CHANNELS.items(): assert "name" in info, f"'{channel_id}' fehlt 'name'" assert "aliases" in info, f"'{channel_id}' fehlt 'aliases'" assert "group" in info, f"'{channel_id}' fehlt 'group'" assert "xmltv_ids" in info, f"'{channel_id}' fehlt 'xmltv_ids'" def test_channels_aliase_sind_listen(self) -> None: """Alle Alias-Felder muessen Listen sein.""" for channel_id, info in CHANNELS.items(): assert isinstance(info["aliases"], list), ( f"'{channel_id}' aliases ist keine Liste" ) def test_channels_xmltv_ids_sind_listen(self) -> None: """Alle xmltv_ids-Felder muessen Listen sein.""" for channel_id, info in CHANNELS.items(): assert isinstance(info["xmltv_ids"], list), ( f"'{channel_id}' xmltv_ids ist keine Liste" ) # ============================================================================ # ChannelMapper - resolve() # ============================================================================ class TestChannelMapperResolve: """Tests fuer die Namensaufloesung ueber resolve().""" @pytest.fixture def mapper(self) -> ChannelMapper: """Standard-Mapper ohne Filter oder benutzerdefinierte Aliase.""" return ChannelMapper() def test_resolve_exakt_rtl2(self, mapper: ChannelMapper) -> None: """Exakter Match: 'RTL2' wird auf 'rtl2' aufgeloest.""" assert mapper.resolve("RTL2") == "rtl2" def test_resolve_exakt_prosieben(self, mapper: ChannelMapper) -> None: """Exakter Match: 'ProSieben' wird auf 'pro7' aufgeloest.""" assert mapper.resolve("ProSieben") == "pro7" def test_resolve_exakt_ard(self, mapper: ChannelMapper) -> None: """Exakter Match: 'ARD' wird auf 'ard' aufgeloest.""" assert mapper.resolve("ARD") == "ard" def test_resolve_gross_kleinschreibung_rtl2(self, mapper: ChannelMapper) -> None: """Gross-/Kleinschreibung wird ignoriert: 'rtl2' -> 'rtl2'.""" assert mapper.resolve("rtl2") == "rtl2" def test_resolve_gross_kleinschreibung_prosieben(self, mapper: ChannelMapper) -> None: """Gross-/Kleinschreibung wird ignoriert: 'PROSIEBEN' -> 'pro7'.""" assert mapper.resolve("PROSIEBEN") == "pro7" def test_resolve_gross_kleinschreibung_zdf(self, mapper: ChannelMapper) -> None: """Gross-/Kleinschreibung wird ignoriert: 'zdf' -> 'zdf'.""" assert mapper.resolve("zdf") == "zdf" def test_resolve_alias_pro7(self, mapper: ChannelMapper) -> None: """Alias-Match: 'Pro 7' wird auf 'pro7' aufgeloest.""" assert mapper.resolve("Pro 7") == "pro7" def test_resolve_alias_sat_eins(self, mapper: ChannelMapper) -> None: """Alias-Match: 'Sat eins' wird auf 'sat1' aufgeloest.""" assert mapper.resolve("Sat eins") == "sat1" def test_resolve_alias_rtl_zwei(self, mapper: ChannelMapper) -> None: """Alias-Match: 'RTL Zwei' wird auf 'rtl2' aufgeloest.""" assert mapper.resolve("RTL Zwei") == "rtl2" def test_resolve_alias_rtl_ii(self, mapper: ChannelMapper) -> None: """Alias-Match: 'RTL II' wird auf 'rtl2' aufgeloest.""" assert mapper.resolve("RTL II") == "rtl2" def test_resolve_teilstring_pro7_maxx(self, mapper: ChannelMapper) -> None: """Teilstring-Match: 'Pro7 Maxx' wird auf 'pro7_maxx' aufgeloest.""" assert mapper.resolve("Pro7 Maxx") == "pro7_maxx" def test_resolve_unbekannter_sender_none(self, mapper: ChannelMapper) -> None: """Unbekannter Sendername gibt None zurueck.""" assert mapper.resolve("Unbekannter Sender XYZ") is None def test_resolve_leerer_string_none(self, mapper: ChannelMapper) -> None: """Leerer String gibt None zurueck.""" assert mapper.resolve("") is None def test_resolve_whitespace_wird_gestrippt(self, mapper: ChannelMapper) -> None: """Fuehrende und abschliessende Leerzeichen werden entfernt.""" assert mapper.resolve(" RTL ") == "rtl" def test_resolve_channel_id_direkt(self, mapper: ChannelMapper) -> None: """Die Sender-ID selbst wird als Alias erkannt.""" assert mapper.resolve("ard") == "ard" def test_resolve_display_name(self, mapper: ChannelMapper) -> None: """Der Display-Name wird als Alias erkannt.""" assert mapper.resolve("Das Erste") == "ard" # ============================================================================ # ChannelMapper - resolve_xmltv_id() # ============================================================================ class TestChannelMapperResolveXmltvId: """Tests fuer die XMLTV-ID-Aufloesung.""" @pytest.fixture def mapper(self) -> ChannelMapper: return ChannelMapper() def test_resolve_xmltv_id_das_erste(self, mapper: ChannelMapper) -> None: """XMLTV-ID 'DasErste.de' wird auf 'ard' aufgeloest.""" assert mapper.resolve_xmltv_id("DasErste.de") == "ard" def test_resolve_xmltv_id_prosieben(self, mapper: ChannelMapper) -> None: """XMLTV-ID 'ProSieben.de' wird auf 'pro7' aufgeloest.""" assert mapper.resolve_xmltv_id("ProSieben.de") == "pro7" def test_resolve_xmltv_id_zdf(self, mapper: ChannelMapper) -> None: """XMLTV-ID 'ZDF.de' wird auf 'zdf' aufgeloest.""" assert mapper.resolve_xmltv_id("ZDF.de") == "zdf" def test_resolve_xmltv_id_unbekannt_none(self, mapper: ChannelMapper) -> None: """Unbekannte XMLTV-ID gibt None zurueck.""" assert mapper.resolve_xmltv_id("UnbekannterSender.de") is None def test_resolve_xmltv_id_alternative_id(self, mapper: ChannelMapper) -> None: """Alternative XMLTV-ID 'ARD.de' wird ebenfalls auf 'ard' aufgeloest.""" assert mapper.resolve_xmltv_id("ARD.de") == "ard" # ============================================================================ # ChannelMapper - get_display_name() # ============================================================================ class TestChannelMapperGetDisplayName: """Tests fuer die Display-Name-Abfrage.""" @pytest.fixture def mapper(self) -> ChannelMapper: return ChannelMapper() def test_display_name_rtl2(self, mapper: ChannelMapper) -> None: """Display-Name fuer 'rtl2' ist 'RTLZWEI'.""" assert mapper.get_display_name("rtl2") == "RTLZWEI" def test_display_name_ard(self, mapper: ChannelMapper) -> None: """Display-Name fuer 'ard' ist 'Das Erste'.""" assert mapper.get_display_name("ard") == "Das Erste" def test_display_name_unbekannt_fallback(self, mapper: ChannelMapper) -> None: """Unbekannte Sender-ID gibt die ID selbst als Fallback zurueck.""" assert mapper.get_display_name("unbekannt_123") == "unbekannt_123" # ============================================================================ # ChannelMapper - get_all_channel_ids() # ============================================================================ class TestChannelMapperGetAllChannelIds: """Tests fuer die Abfrage aller aktiven Sender-IDs.""" def test_alle_sender_ohne_filter(self) -> None: """Ohne Filter werden alle Sender zurueckgegeben.""" mapper = ChannelMapper() ids = mapper.get_all_channel_ids() assert len(ids) == len(CHANNELS) def test_alle_sender_ist_liste(self) -> None: """Die Rueckgabe ist eine Liste.""" mapper = ChannelMapper() ids = mapper.get_all_channel_ids() assert isinstance(ids, list) def test_alle_sender_enthaelt_ard(self) -> None: """Die Liste enthaelt 'ard'.""" mapper = ChannelMapper() ids = mapper.get_all_channel_ids() assert "ard" in ids # ============================================================================ # ChannelMapper - channel_filter # ============================================================================ class TestChannelMapperFilter: """Tests fuer die Sender-Filterung.""" def test_filter_nur_ard_zdf(self) -> None: """Mit Filter ['ard', 'zdf'] werden nur 2 Sender aktiv.""" mapper = ChannelMapper(channel_filter=["ard", "zdf"]) ids = mapper.get_all_channel_ids() assert set(ids) == {"ard", "zdf"} def test_filter_resolve_aktiver_sender(self) -> None: """Aktive Sender koennen ueber resolve() gefunden werden.""" mapper = ChannelMapper(channel_filter=["rtl"]) assert mapper.resolve("RTL") == "rtl" def test_filter_resolve_inaktiver_sender_none(self) -> None: """Inaktive (gefilterte) Sender geben None zurueck.""" mapper = ChannelMapper(channel_filter=["rtl"]) assert mapper.resolve("ARD") is None def test_filter_xmltv_nur_aktive(self) -> None: """XMLTV-IDs gefilterter Sender sind nicht verfuegbar.""" mapper = ChannelMapper(channel_filter=["rtl"]) assert mapper.resolve_xmltv_id("DasErste.de") is None assert mapper.resolve_xmltv_id("RTL.de") == "rtl" # ============================================================================ # ChannelMapper - custom_aliases # ============================================================================ class TestChannelMapperCustomAliases: """Tests fuer benutzerdefinierte Aliase.""" def test_custom_alias_ueberschreibt(self) -> None: """Benutzerdefinierter Alias wird korrekt aufgeloest.""" mapper = ChannelMapper(custom_aliases={"Mein Sender": "rtl2"}) assert mapper.resolve("Mein Sender") == "rtl2" def test_custom_alias_aktiviert_sender(self) -> None: """Benutzerdefinierter Alias aktiviert einen gefilterten Sender.""" mapper = ChannelMapper( channel_filter=["ard"], custom_aliases={"Lieblingssender": "rtl"}, ) ids = mapper.get_all_channel_ids() assert "rtl" in ids def test_custom_alias_ungueltiger_sender_ignoriert(self) -> None: """Alias auf nicht existierenden Sender wird ignoriert.""" mapper = ChannelMapper(custom_aliases={"Test": "existiert_nicht"}) assert mapper.resolve("Test") is None class TestChannelMapperBlacklist: """Tests fuer die Blacklist-Funktion.""" def test_blacklist_schliesst_sender_aus(self) -> None: """Sender auf der Blacklist werden nicht aufgenommen.""" mapper = ChannelMapper(blacklist=["rtl", "rtl2"]) ids = mapper.get_all_channel_ids() assert "rtl" not in ids assert "rtl2" not in ids assert "ard" in ids def test_blacklist_resolve_gibt_none(self) -> None: """Geblacklister Sender kann nicht aufgeloest werden.""" mapper = ChannelMapper(blacklist=["vox"]) assert mapper.resolve("VOX") is None assert mapper.resolve("Vox") is None def test_blacklist_case_insensitive(self) -> None: """Blacklist-Vergleich ist case-insensitive.""" mapper = ChannelMapper(blacklist=["PRO7", "RTL2"]) ids = mapper.get_all_channel_ids() assert "pro7" not in ids assert "rtl2" not in ids def test_blacklist_andere_sender_bleiben(self) -> None: """Nicht geblackliste Sender bleiben verfuegbar.""" mapper = ChannelMapper(blacklist=["vox"]) ids = mapper.get_all_channel_ids() assert "vox" not in ids assert len(ids) == len(CHANNELS) - 1 def test_whitelist_hat_vorrang_vor_blacklist(self) -> None: """Wenn Whitelist gesetzt, wird Blacklist ignoriert.""" mapper = ChannelMapper( channel_filter=["ard", "zdf", "rtl"], blacklist=["rtl"], ) ids = mapper.get_all_channel_ids() # RTL ist auf Whitelist → Blacklist wird ignoriert assert "rtl" in ids assert len(ids) == 3 def test_leere_blacklist_aendert_nichts(self) -> None: """Leere Blacklist hat keine Auswirkung.""" mapper_normal = ChannelMapper() mapper_empty = ChannelMapper(blacklist=[]) assert len(mapper_normal.get_all_channel_ids()) == len(mapper_empty.get_all_channel_ids()) def test_blacklist_xmltv_ids_auch_ausgeschlossen(self) -> None: """XMLTV-IDs von geblacklisteten Sendern werden nicht aufgeloest.""" mapper = ChannelMapper(blacklist=["rtl"]) assert mapper.resolve_xmltv_id("RTL.de") is None