package risk import ( "testing" ) func makeHours(temps []float64) []HourlyData { hours := make([]HourlyData, len(temps)) for i, t := range temps { hours[i] = HourlyData{ Hour: i, TempC: t, ApparentC: t, HumidityPct: 50, IsDay: i >= 6 && i < 21, } } return hours } func TestAnalyzeDay_CoolDay(t *testing.T) { temps := make([]float64, 24) for i := range temps { temps[i] = 20 + float64(i%5) // 20-24C } result := AnalyzeDay(makeHours(temps), DefaultThresholds()) if result.Level != Low { t.Errorf("Level = %v, want Low", result.Level) } if len(result.Windows) != 0 { t.Errorf("Windows = %d, want 0", len(result.Windows)) } } func TestAnalyzeDay_ModeratelyHot(t *testing.T) { temps := make([]float64, 24) for i := range temps { temps[i] = 18 // base below poor night cooling threshold } // Hot window 11-15 for i := 11; i <= 15; i++ { temps[i] = 32 } result := AnalyzeDay(makeHours(temps), DefaultThresholds()) if result.Level != Moderate { t.Errorf("Level = %v, want Moderate", result.Level) } if len(result.Windows) != 1 { t.Fatalf("Windows = %d, want 1", len(result.Windows)) } w := result.Windows[0] if w.StartHour != 11 || w.EndHour != 15 { t.Errorf("Window = %d-%d, want 11-15", w.StartHour, w.EndHour) } if w.PeakTempC != 32 { t.Errorf("PeakTempC = %v, want 32", w.PeakTempC) } } func TestAnalyzeDay_VeryHot(t *testing.T) { temps := make([]float64, 24) for i := range temps { temps[i] = 18 // below poor night cooling threshold } for i := 10; i <= 17; i++ { temps[i] = 37 } result := AnalyzeDay(makeHours(temps), DefaultThresholds()) if result.Level != High { t.Errorf("Level = %v, want High", result.Level) } } func TestAnalyzeDay_Extreme(t *testing.T) { temps := make([]float64, 24) for i := range temps { temps[i] = 25 } for i := 12; i <= 16; i++ { temps[i] = 41 } result := AnalyzeDay(makeHours(temps), DefaultThresholds()) if result.Level != Extreme { t.Errorf("Level = %v, want Extreme", result.Level) } } func TestAnalyzeDay_PoorNightCoolingElevates(t *testing.T) { temps := make([]float64, 24) for i := range temps { temps[i] = 22 } // Hot day window for i := 11; i <= 15; i++ { temps[i] = 32 } // Poor night cooling (hour 0-6 and 21-23 above 20C) for i := 0; i <= 6; i++ { temps[i] = 22 } for i := 21; i < 24; i++ { temps[i] = 22 } result := AnalyzeDay(makeHours(temps), DefaultThresholds()) if !result.PoorNightCool { t.Error("expected PoorNightCool = true") } // Base Moderate + poor night = High if result.Level != High { t.Errorf("Level = %v, want High (elevated from Moderate)", result.Level) } } func TestAnalyzeDay_GoodNightCooling(t *testing.T) { temps := make([]float64, 24) for i := range temps { temps[i] = 18 // cool nights } for i := 11; i <= 15; i++ { temps[i] = 32 } result := AnalyzeDay(makeHours(temps), DefaultThresholds()) if result.PoorNightCool { t.Error("expected PoorNightCool = false") } if result.Level != Moderate { t.Errorf("Level = %v, want Moderate (no elevation)", result.Level) } } func TestAnalyzeDay_Empty(t *testing.T) { result := AnalyzeDay(nil, DefaultThresholds()) if result.Level != Low { t.Errorf("Level = %v, want Low", result.Level) } } func TestAnalyzeDay_MinNightTemp(t *testing.T) { temps := make([]float64, 24) for i := range temps { temps[i] = 25 } temps[3] = 16.5 // coldest night hour result := AnalyzeDay(makeHours(temps), DefaultThresholds()) if result.MinNightTempC != 16.5 { t.Errorf("MinNightTempC = %v, want 16.5", result.MinNightTempC) } } func TestRiskLevelString(t *testing.T) { tests := []struct { level RiskLevel want string }{ {Low, "low"}, {Moderate, "moderate"}, {High, "high"}, {Extreme, "extreme"}, {RiskLevel(99), "unknown"}, } for _, tt := range tests { if got := tt.level.String(); got != tt.want { t.Errorf("RiskLevel(%d).String() = %s, want %s", tt.level, got, tt.want) } } }