Files
loogle-scripts/services/telegram-bot/test_previsione7_interpretation.py
T
2026-08-21 11:57:29 +02:00

179 lines
6.2 KiB
Python

#!/usr/bin/env python3
"""Regression checks for Meteo7 interpretation (weathercode mode, ice gates, hours, trend max/min)."""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from previsione7 import (
_merge_weathercode,
_format_event_hours,
analyze_daily_events,
analyze_temperature_trend,
format_detailed_trend_explanation,
get_precip_type,
)
def test_weathercode_mode_not_median():
# 61 (rain) + 71 (snow) → mediana numerica sarebbe 66 (FZRA); moda deve evitare 66
assert _merge_weathercode([61, 71], preferred=61) == 61
assert _merge_weathercode([61, 71], preferred=71) == 71
assert _merge_weathercode([61, 61, 71]) == 61
assert _merge_weathercode([66, 66, 61]) == 66
print("OK weathercode mode")
def test_get_precip_type_temp_gate():
assert "Congelantesi" not in get_precip_type(67, temp=28.0)
assert "Pioggia" in get_precip_type(67, temp=28.0)
assert "Congelantesi" in get_precip_type(67, temp=0.5)
assert "Neve" not in get_precip_type(71, temp=20.0)
assert "Neve" in get_precip_type(71, temp=-1.0)
print("OK precip type temp gate")
def test_gelicidio_hot_air_no_event():
times = [f"2026-07-21T{h:02d}:00" for h in range(24)]
codes = [0] * 24
codes[20] = 67 # FZRA spurio
precip = [0.0] * 24
precip[20] = 1.2
temps = [28.0] * 24
dewpoints = [18.0] * 24
winds = [5.0] * 24
events = analyze_daily_events(
times, codes, None, precip, winds, temps, dewpoints,
snowfalls=[0.0] * 24, rains=precip[:], soil_temps=[25.0] * 24,
cloud_covers=[50.0] * 24, wind_speeds=winds,
)
ice_like = [e for e in events if "GELICIDIO" in e or "BRINA" in e or "Gelata" in e or "Black Ice" in e]
assert not ice_like, f"unexpected ice events in heat: {ice_like}"
rain_like = [e for e in events if "Pioggia" in e or "Congelantesi" in e]
assert rain_like, "expected rain event"
assert all("Congelantesi" not in e for e in rain_like)
print("OK no gelicidio at 28°C")
def test_single_hour_event_range():
times = [f"2026-07-21T{h:02d}:00" for h in range(24)]
assert _format_event_hours(times, 20, 20) == "20:00-21:00"
assert _format_event_hours(times, 20, 21) == "20:00-22:00"
# last hour of day
assert _format_event_hours(times, 23, 23) == "23:00-00:00"
codes = [0] * 24
precip = [0.0] * 24
precip[20] = 2.0
temps = [22.0] * 24
events = analyze_daily_events(
times, codes, None, precip, [5.0] * 24, temps, [12.0] * 24,
snowfalls=[0.0] * 24, rains=precip[:],
)
rain_ev = [e for e in events if "🕒" in e]
assert rain_ev, events
assert "20:00-21:00" in rain_ev[0]
assert "20:00-20:00" not in rain_ev[0]
print("OK single-hour 20:00-21:00")
def test_trend_max_min_not_media():
# Heatwave: max stay high, slight drop → calo_termico not fronte_freddo
tmax = [34, 35, 36, 33, 30, 29, 28, 27, 26, 25]
tmin = [22, 23, 24, 21, 20, 19, 18, 17, 16, 15]
trend = analyze_temperature_trend(tmax, tmin, days=10)
assert trend is not None
assert "first_max" in trend and "first_min" in trend
assert trend["type"] == "calo_termico"
text = format_detailed_trend_explanation(trend, daily_time_list=[f"2026-07-{21+i:02d}" for i in range(10)])
assert "media" not in text.lower()
assert "Massime:" in text and "Minime:" in text
assert "Fronte Freddo" not in text
print("OK trend max/min calo_termico")
def test_real_gelicidio_cold():
times = [f"2026-01-10T{h:02d}:00" for h in range(24)]
codes = [0] * 24
codes[8] = 67
precip = [0.0] * 24
precip[8] = 0.5
temps = [5.0] * 24
temps[8] = -0.5
events = analyze_daily_events(
times, codes, None, precip, [3.0] * 24, temps, [-1.0] * 24,
snowfalls=[0.0] * 24, rains=precip[:], soil_temps=[-1.0] * 24,
cloud_covers=[80.0] * 24, wind_speeds=[3.0] * 24,
)
assert any("GELICIDIO" in e for e in events), events
print("OK real gelicidio at subzero")
def test_monday_storm_event_mm_is_hourly_sum():
"""15:00=17.4 + 16:00=5.0 → un evento 22.4 mm, non 5 mm né 22.4 ripetuto."""
times = [f"2026-08-17T{h:02d}:00" for h in range(24)]
precip = [0.0] * 24
precip[15] = 17.4
precip[16] = 5.0
codes = [3] * 24
codes[15] = 65
codes[16] = 63
temps = [26.0] * 24
events = analyze_daily_events(
times, codes, None, precip, [18.0] * 24, temps, [16.0] * 24,
snowfalls=[0.0] * 24, rains=precip[:],
)
rain_ev = [e for e in events if "🕒" in e]
assert len(rain_ev) == 1, rain_ev
assert "15:00-17:00" in rain_ev[0]
assert "22.4mm" in rain_ev[0]
assert rain_ev[0].count("22.4mm") == 1
print("OK lun 17 15-17h = 22.4mm")
def test_three_pulses_keep_own_mm_not_daily_total():
times = [f"2026-08-16T{h:02d}:00" for h in range(24)]
precip = [0.0] * 24
precip[10] = 18.0
precip[14] = 19.0
precip[18] = 20.0
events = analyze_daily_events(
times, [63] * 24, None, precip, [10.0] * 24, [24.0] * 24, [14.0] * 24,
snowfalls=[0.0] * 24, rains=precip[:],
)
rain_ev = [e for e in events if "🕒" in e]
assert len(rain_ev) == 3, rain_ev
assert "18.0mm" in rain_ev[0]
assert "19.0mm" in rain_ev[1]
assert "20.0mm" in rain_ev[2]
assert all("57.0mm" not in e for e in rain_ev)
print("OK tre fasce con mm propri")
def test_last_hour_rain_is_emitted():
times = [f"2026-08-17T{h:02d}:00" for h in range(24)]
precip = [0.0] * 24
precip[23] = 4.2
events = analyze_daily_events(
times, [61] * 24, None, precip, [8.0] * 24, [20.0] * 24, [12.0] * 24,
snowfalls=[0.0] * 24, rains=precip[:],
)
rain_ev = [e for e in events if "🕒" in e]
assert rain_ev, events
assert "23:00-00:00" in rain_ev[0]
assert "4.2mm" in rain_ev[0]
print("OK pioggia ultima ora del giorno")
if __name__ == "__main__":
test_weathercode_mode_not_median()
test_get_precip_type_temp_gate()
test_gelicidio_hot_air_no_event()
test_single_hour_event_range()
test_trend_max_min_not_media()
test_real_gelicidio_cold()
test_monday_storm_event_mm_is_hourly_sum()
test_three_pulses_keep_own_mm_not_daily_total()
test_last_hour_rain_is_emitted()
print("\nAll interpretation regression checks passed.")