Correct daypart identity and display handling

This commit is contained in:
2026-08-13 01:08:20 +00:00
parent 13829cc65c
commit 41b86109e3
9 changed files with 224 additions and 24 deletions

View File

@@ -82,6 +82,40 @@ func TestDefaults(t *testing.T) {
}
}
func TestDaypartNamesMustHaveDistinctCanonicalIdentities(t *testing.T) {
tests := []struct {
name string
names []string
wantErr string
}{
{name: "exact duplicate", names: []string{"morning", "morning"}, wantErr: "conflicts with"},
{name: "case-only duplicate", names: []string{"morning", "MORNING"}, wantErr: "conflicts with"},
{name: "punctuation-normalized duplicate", names: []string{"morning", "morning!"}, wantErr: "conflicts with"},
{name: "distinct Unicode names", names: []string{"mañana", "manana"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := Defaults()
cfg.Dayparts = make([]DaypartConfig, 0, len(tt.names))
for _, name := range tt.names {
cfg.Dayparts = append(cfg.Dayparts, DaypartConfig{Name: name, Start: "06:00", End: "12:00"})
}
err := Validate(cfg)
if tt.wantErr == "" {
if err != nil {
t.Fatalf("Validate() error = %v", err)
}
return
}
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
t.Fatalf("Validate() error = %v, want %q", err, tt.wantErr)
}
})
}
}
func TestWeatherAPIBaseURLValidation(t *testing.T) {
tests := []struct {
name string

View File

@@ -5,6 +5,7 @@ import (
"net/url"
"strings"
"gitea.maximumdirect.net/eric/weatherreporter/internal/forecast"
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
)
@@ -74,10 +75,16 @@ func Validate(cfg Config) error {
if len(cfg.Dayparts) == 0 {
return fmt.Errorf("dayparts must contain at least one entry")
}
daypartNames := make(map[string]int, len(cfg.Dayparts))
for i, daypart := range cfg.Dayparts {
if strings.TrimSpace(daypart.Name) == "" {
return fmt.Errorf("dayparts[%d].name is required", i)
}
key := forecast.CanonicalDaypartKey(daypart.Name)
if previous, exists := daypartNames[key]; exists {
return fmt.Errorf("dayparts[%d].name %q conflicts with dayparts[%d].name after canonicalization", i, daypart.Name, previous)
}
daypartNames[key] = i
if _, err := timeutil.ParseClock(daypart.Start); err != nil {
return fmt.Errorf("dayparts[%d].start is invalid: %w", i, err)
}