Add server-side rendered setup UI accessible via `heatwave web`. The dashboard is now re-rendered per request and includes a nav bar linking to the new /setup page. Setup provides full CRUD for profiles, rooms, devices, occupants, AC units (with room assignment), scenario toggles, and forecast fetching — all via POST/redirect/GET forms. - Add ShowNav field to DashboardData for conditional nav bar - Extract fetchForecastForProfile() for reuse by web handler - Create setup.html.tmpl with Tailwind-styled entity sections - Create web_handlers.go with 15 route handlers and flash cookies - Switch web.go from pre-rendered to per-request dashboard rendering - Graceful dashboard fallback when no forecast data exists
51 lines
1.2 KiB
Go
51 lines
1.2 KiB
Go
package action
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/cnachtigall/heatwave-autopilot/internal/heat"
|
|
"github.com/cnachtigall/heatwave-autopilot/internal/risk"
|
|
)
|
|
|
|
func TestBuildTimeline_24Slots(t *testing.T) {
|
|
contexts := make([]HourContext, 24)
|
|
for i := range contexts {
|
|
contexts[i] = HourContext{
|
|
Hour: i,
|
|
TempC: 20 + float64(i),
|
|
RiskLevel: risk.Low,
|
|
BudgetStatus: heat.Comfortable,
|
|
IsDay: i >= 6 && i < 21,
|
|
}
|
|
}
|
|
|
|
actions := []Action{
|
|
{ID: "test_action", When: TimeCondition{MinTempC: 30}, Impact: ImpactHigh, Effort: EffortNone},
|
|
}
|
|
|
|
slots := BuildTimeline(contexts, actions)
|
|
if len(slots) != 24 {
|
|
t.Fatalf("slots = %d, want 24", len(slots))
|
|
}
|
|
|
|
// Check hour assignment
|
|
for i, s := range slots {
|
|
if s.Hour != i {
|
|
t.Errorf("slot[%d].Hour = %d, want %d", i, s.Hour, i)
|
|
}
|
|
if s.TempC != 20+float64(i) {
|
|
t.Errorf("slot[%d].TempC = %v, want %v", i, s.TempC, 20+float64(i))
|
|
}
|
|
}
|
|
|
|
// test_action matches hours with temp >= 30 (hours 10-23)
|
|
for i, s := range slots {
|
|
if i >= 10 && len(s.Actions) == 0 {
|
|
t.Errorf("slot[%d] should have actions (temp=%v)", i, s.TempC)
|
|
}
|
|
if i < 10 && len(s.Actions) > 0 {
|
|
t.Errorf("slot[%d] should not have actions (temp=%v)", i, s.TempC)
|
|
}
|
|
}
|
|
}
|