meshai/work/tests/test_evac_phase.py
Matt Johnson c4706d3c92 fix(ipaws): route county-only alerts through evac-phase detection
Adds meshai.notifications.evac_phase.detect_phase, wired into the IPAWS
formatter/adapter, to classify READY/SET/GO evacuation phases from real
FEMA IPAWS alert headline/CMAMtext strings. Includes explicit
false-positive guards since a wrong GO detection would broadcast an
evacuation order that was never issued.
2026-08-16 01:19:46 +00:00

76 lines
2.9 KiB
Python

"""Tests for meshai.notifications.evac_phase.detect_phase.
Cases are drawn from REAL FEMA IPAWS alert headline/CMAMtext/description
strings (see tests/fixtures/ipaws/) plus explicit false-positive guards, since
a wrong GO detection would broadcast an evacuation order that was never
issued.
"""
from __future__ import annotations
import pytest
from meshai.notifications.evac_phase import detect_phase
# ============================================================
# real strings -> expected phase
# ============================================================
@pytest.mark.parametrize("text, expected", [
("LEVEL 1 READY - Evacuation Status", "READY"),
("Level 2 Set Alert", "SET"),
("LEVEL I SET Alert", "SET"), # word beats numeral; err upward
("Level 3 - Go Now", "GO"),
("Level 3- Go Now", "GO"),
("Ohio Gulch GO Evacuation Status", "GO"),
("Indian Creek Set to GO.", "GO"), # highest wins, NOT SET
("Immediate Evacuation", "GO"),
("Prepare to Evacuate", "SET"),
("BRUSH FIRE", None),
("Owyhee County Closure Area", None),
("Endangered Missing Person Alert", None),
(
"Jackson County Sheriff's Office- Level 3 GO NOW evacuation notice "
"UPGRADED for JAC-126",
"GO",
),
])
def test_detect_phase_real_strings(text, expected):
assert detect_phase(text) == expected
# ============================================================
# false-positive guards — bare lowercase / narrative usage must NOT match
# ============================================================
@pytest.mark.parametrize("text", [
"residents should go to the Blaine County Fairgrounds",
"crews are set to arrive by 0600",
"evacuate via Go Creek Road",
])
def test_detect_phase_false_positive_guards(text):
assert detect_phase(text) is None
# ============================================================
# precedence + multi-arg scanning
# ============================================================
def test_precedence_highest_always_wins_regardless_of_arg_order():
# SET language in the first text, GO language in the second — GO must win.
assert detect_phase("Prepare to Evacuate", "Level 3 - Go Now") == "GO"
# Same phrases, arguments reversed — still GO (order-independent).
assert detect_phase("Level 3 - Go Now", "Prepare to Evacuate") == "GO"
def test_detect_phase_scans_all_texts_together():
# No single text alone carries a phase; combined they do (SET here,
# since "LEVEL 2" is an explicit SET phrase and no GO phrase is present).
assert detect_phase("Jackson County Sheriff's Office", "Level 2 Set Alert") == "SET"
def test_detect_phase_none_texts_and_empty_input_are_safe():
assert detect_phase(None, None) is None
assert detect_phase() is None
assert detect_phase("") is None
assert detect_phase(None, "BRUSH FIRE", None) is None