Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions custom_components/cap_alerts/providers/eccc.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,24 @@ def _pick_cap_link(entry: Element) -> tuple[str, str]:
# ---------------------------------------------------------------------------


def _language_matches(info_lang: str, preferred: str) -> bool:
"""Check language match with BCP 47 primary-subtag fallback.

Exact match wins (``en-CA`` == ``en-CA``). When that fails, the primary
subtag (the part before the first ``-``) is compared so that a bare
``en`` info block matches a preferred ``en-CA`` and vice-versa. This
hardens against CAP documents that declare a bare primary subtag
instead of the full region-tagged form the ECCC feed normally carries.
"""
if not info_lang or not preferred:
return False
if info_lang == preferred:
return True
return (
preferred.split("-", 1)[0].casefold() == info_lang.split("-", 1)[0].casefold()
)


def _select_info(doc: CAPDoc, language: str) -> CAPInfoDoc:
"""Pick the <info> block matching language; fall back to first.

Expand All @@ -368,7 +386,7 @@ def _select_info(doc: CAPDoc, language: str) -> CAPInfoDoc:
if not doc.infos:
return CAPInfoDoc()
for info in doc.infos:
if info.language == language:
if _language_matches(info.language, language):
return info
return doc.infos[0]

Expand Down Expand Up @@ -423,7 +441,9 @@ def _select_region_info(
province where the alert is still live would be the worse failure.
"""
candidates = (
[info for info in doc.infos if info.language == language] if language else []
[info for info in doc.infos if _language_matches(info.language, language)]
if language
else []
)
if not candidates:
# No block declares this language (single-language document, or a
Expand Down Expand Up @@ -731,7 +751,7 @@ def _merge_languages(variants: list[CAPAlert], preferred_lang: str) -> CAPAlert:
primary = None
alt = None
for v in variants:
if v.language == preferred_lang:
if _language_matches(v.language, preferred_lang):
primary = v
else:
alt = v
Expand Down
34 changes: 34 additions & 0 deletions tests/test_eccc_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def _load_provider(name: str) -> types.ModuleType:
_parse_cap_alert = _cap_mod.parse_cap_alert
_select_info = _eccc_mod._select_info
_select_region_info = _eccc_mod._select_region_info
_language_matches = _eccc_mod._language_matches
_location_status = _eccc_mod._location_status
_is_terminal_info = _eccc_mod._is_terminal_info
_resolve_chain_leaves = _cap_mod.resolve_chain_leaves
Expand Down Expand Up @@ -302,6 +303,39 @@ def test_parse_cap_alert_tolerates_newline_separated_references():
assert doc.references[1][1] == "urn:oid:2.49.0.1.124.test.2026.OLD.EN"


# ---------------------------------------------------------------------------
# _language_matches tests
# ---------------------------------------------------------------------------


def test_language_matches_exact_match():
assert _language_matches("en-CA", "en-CA") is True
assert _language_matches("fr-CA", "fr-CA") is True


def test_language_matches_bare_primary_against_region():
"""Bare 'en' info block should match preferred 'en-CA'."""
assert _language_matches("en", "en-CA") is True
assert _language_matches("en-CA", "en") is True


def test_language_matches_different_primary_subtags():
"""en-CA and fr-CA must not match each other."""
assert _language_matches("en-CA", "fr-CA") is False
assert _language_matches("fr-CA", "en-CA") is False


def test_language_matches_empty_strings():
assert _language_matches("", "en-CA") is False
assert _language_matches("en-CA", "") is False
assert _language_matches("", "") is False


def test_language_matches_case_insensitive():
assert _language_matches("EN-CA", "en-ca") is True
assert _language_matches("en-CA", "EN-ca") is True


# ---------------------------------------------------------------------------
# _select_info tests
# ---------------------------------------------------------------------------
Expand Down