Add regional task templates API with climate zone lookup
Adds a new endpoint GET /api/tasks/templates/by-region/?zip= that resolves ZIP codes to IECC climate regions and returns relevant home maintenance task templates. Includes climate region model, region lookup service with tests, seed data for all 8 climate zones with 50+ templates, and OpenAPI spec. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
81
internal/services/region_lookup_test.go
Normal file
81
internal/services/region_lookup_test.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetClimateRegionIDByState(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
state string
|
||||
expected uint
|
||||
}{
|
||||
{"Massachusetts → Cold (5)", "MA", 5},
|
||||
{"Florida → Hot-Humid (1)", "FL", 1},
|
||||
{"Arizona → Hot-Dry (2)", "AZ", 2},
|
||||
{"Alaska → Arctic (8)", "AK", 8},
|
||||
{"Minnesota → Very Cold (6)", "MN", 6},
|
||||
{"Tennessee → Mixed-Humid (3)", "TN", 3},
|
||||
{"Missouri → Mixed (4)", "MO", 4},
|
||||
{"Unknown state → 0", "XX", 0},
|
||||
{"Empty string → 0", "", 0},
|
||||
{"Lowercase input", "ma", 5},
|
||||
{"Whitespace trimmed", " TX ", 2},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := GetClimateRegionIDByState(tt.state)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestZipToState(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
zip string
|
||||
expected string
|
||||
}{
|
||||
{"Boston MA", "02101", "MA"},
|
||||
{"Miami FL", "33101", "FL"},
|
||||
{"Phoenix AZ", "85001", "AZ"},
|
||||
{"Anchorage AK", "99501", "AK"},
|
||||
{"New York NY", "10001", "NY"},
|
||||
{"Chicago IL", "60601", "IL"},
|
||||
{"Houston TX", "77001", "TX"},
|
||||
{"Denver CO", "80201", "CO"},
|
||||
{"DC", "20001", "DC"},
|
||||
{"Too short", "12", ""},
|
||||
{"Empty", "", ""},
|
||||
{"Non-numeric", "abcde", ""},
|
||||
{"Unrecognized prefix", "00100", ""},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := ZipToState(tt.zip)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateToClimateRegion_AllStatesPresent(t *testing.T) {
|
||||
// All 50 states + DC should be in the map
|
||||
allStates := []string{
|
||||
"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA",
|
||||
"HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD",
|
||||
"MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ",
|
||||
"NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC",
|
||||
"SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY",
|
||||
"DC",
|
||||
}
|
||||
|
||||
for _, state := range allStates {
|
||||
t.Run(state, func(t *testing.T) {
|
||||
regionID := GetClimateRegionIDByState(state)
|
||||
assert.Greater(t, regionID, uint(0), "State %s should map to a region", state)
|
||||
assert.LessOrEqual(t, regionID, uint(8), "State %s region should be 1-8, got %d", state, regionID)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user