package action import ( "testing" "github.com/cnachtigall/heatwave-autopilot/internal/heat" "github.com/cnachtigall/heatwave-autopilot/internal/risk" ) func TestMatches_TempThreshold(t *testing.T) { a := Action{When: TimeCondition{MinTempC: 30}} if Matches(a, HourContext{TempC: 35}) != true { t.Error("should match at 35C") } if Matches(a, HourContext{TempC: 25}) != false { t.Error("should not match at 25C") } } func TestMatches_HourRange(t *testing.T) { a := Action{When: TimeCondition{HourFrom: 6, HourTo: 9}} if Matches(a, HourContext{Hour: 7}) != true { t.Error("should match at hour 7") } if Matches(a, HourContext{Hour: 12}) != false { t.Error("should not match at hour 12") } } func TestMatches_NightOnly(t *testing.T) { a := Action{When: TimeCondition{NightOnly: true}} if Matches(a, HourContext{IsDay: false}) != true { t.Error("should match at night") } if Matches(a, HourContext{IsDay: true}) != false { t.Error("should not match during day") } } func TestMatches_MinRisk(t *testing.T) { a := Action{When: TimeCondition{MinRisk: "high"}} if Matches(a, HourContext{RiskLevel: risk.High}) != true { t.Error("should match High") } if Matches(a, HourContext{RiskLevel: risk.Extreme}) != true { t.Error("should match Extreme") } if Matches(a, HourContext{RiskLevel: risk.Moderate}) != false { t.Error("should not match Moderate") } if Matches(a, HourContext{RiskLevel: risk.Low}) != false { t.Error("should not match Low") } } func TestMatches_BudgetStatus(t *testing.T) { a := Action{When: TimeCondition{BudgetStatus: "marginal"}} if Matches(a, HourContext{BudgetStatus: heat.Marginal}) != true { t.Error("should match Marginal") } if Matches(a, HourContext{BudgetStatus: heat.Overloaded}) != true { t.Error("should match Overloaded") } if Matches(a, HourContext{BudgetStatus: heat.Comfortable}) != false { t.Error("should not match Comfortable") } } func TestMatches_HighHumidity(t *testing.T) { a := Action{When: TimeCondition{HighHumidity: true, MinTempC: 26}} if Matches(a, HourContext{HumidityPct: 80, TempC: 30}) != true { t.Error("should match at 80% humidity") } if Matches(a, HourContext{HumidityPct: 50, TempC: 30}) != false { t.Error("should not match at 50% humidity") } } func TestSelectActions_SortedByPriority(t *testing.T) { actions := []Action{ {ID: "low_impact_high_effort", Impact: ImpactLow, Effort: EffortHigh}, {ID: "high_impact_no_effort", Impact: ImpactHigh, Effort: EffortNone}, {ID: "med_impact_low_effort", Impact: ImpactMedium, Effort: EffortLow}, } ctx := HourContext{TempC: 35, Hour: 12, IsDay: true} result := SelectActions(actions, ctx) if len(result) != 3 { t.Fatalf("len = %d, want 3", len(result)) } if result[0].ID != "high_impact_no_effort" { t.Errorf("first = %s, want high_impact_no_effort", result[0].ID) } if result[1].ID != "med_impact_low_effort" { t.Errorf("second = %s, want med_impact_low_effort", result[1].ID) } if result[2].ID != "low_impact_high_effort" { t.Errorf("third = %s, want low_impact_high_effort", result[2].ID) } }