Refactored the derived_daily_summary module to utilize narrative forecast data where available
This commit is contained in:
@@ -24,14 +24,17 @@ func TestDerivedDailySummaryModulePackagesOrdinaryForecast(t *testing.T) {
|
||||
}
|
||||
value := moduleValue[DerivedDailySummaryModule](t, output)
|
||||
|
||||
if value.HighTempF == nil || *value.HighTempF != 96 || value.LowTempF == nil || *value.LowTempF != 31 {
|
||||
t.Fatalf("daily temperatures = %#v/%#v, want 96/31", value.HighTempF, value.LowTempF)
|
||||
if value.HighTempF == nil || *value.HighTempF != 88 || value.LowTempF == nil || *value.LowTempF != 64 {
|
||||
t.Fatalf("daily temperatures = %#v/%#v, want narrative 88/64", value.HighTempF, value.LowTempF)
|
||||
}
|
||||
if value.MaxPopPercent == nil || *value.MaxPopPercent != 80 || value.MaxPopWindow != "12 PM-6 PM" {
|
||||
t.Fatalf("max precip = %#v %q, want 80 and afternoon window", value.MaxPopPercent, value.MaxPopWindow)
|
||||
if value.DailyPrecipitationProbability == nil || *value.DailyPrecipitationProbability != 55 {
|
||||
t.Fatalf("DailyPrecipitationProbability = %#v, want narrative 55", value.DailyPrecipitationProbability)
|
||||
}
|
||||
if value.FirstPrecipHour != "8 AM" || value.LastPrecipHour != "2 PM" || !value.ThunderMentioned {
|
||||
t.Fatalf("precip timing = %#v, want threshold windows from morning through afternoon thunder", value)
|
||||
if value.MostLikelyPrecipitationHour != "80% at 12 PM" || !value.ThunderMentioned {
|
||||
t.Fatalf("precip timing = %#v, want most likely hour and thunder", value)
|
||||
}
|
||||
if strings.Join(value.DominantConditions, "|") != "Morning storms, then partly sunny.|Clouds linger tonight." {
|
||||
t.Fatalf("DominantConditions = %#v, want ordered narrative conditions", value.DominantConditions)
|
||||
}
|
||||
if value.MaxWindGustMph == nil || *value.MaxWindGustMph != 42 {
|
||||
t.Fatalf("MaxWindGustMph = %#v, want 42", value.MaxWindGustMph)
|
||||
@@ -44,16 +47,43 @@ func TestDerivedDailySummaryModulePackagesOrdinaryForecast(t *testing.T) {
|
||||
t.Fatalf("marshal daily summary: %v", err)
|
||||
}
|
||||
jsonText := string(data)
|
||||
for _, field := range []string{"high_temp_f", "low_temp_f", "max_pop_percent", "first_precip_hour", "heat_index_max_f"} {
|
||||
for _, field := range []string{"high_temp_f", "low_temp_f", "daily_precipitation_probability", "most_likely_precipitation_hour", "heat_index_max_f"} {
|
||||
if !strings.Contains(jsonText, field) {
|
||||
t.Fatalf("daily json = %s, want field %s", jsonText, field)
|
||||
}
|
||||
}
|
||||
for _, removed := range []string{"max_pop_percent", "max_pop_window", "first_precip_hour", "last_precip_hour"} {
|
||||
if strings.Contains(jsonText, removed) {
|
||||
t.Fatalf("daily json = %s, want removed field %s omitted", jsonText, removed)
|
||||
}
|
||||
}
|
||||
if strings.Contains(jsonText, "qpf") {
|
||||
t.Fatalf("daily json = %s, want no QPF fields without upstream QPF facts", jsonText)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDerivedDailySummaryModuleFallsBackWithoutNarrativeFacts(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
ctx := derivedModuleContext(report.DailyToday)
|
||||
ctx.Derived.DailySummaries[0].NarrativePeriods = nil
|
||||
|
||||
output, err := registry.BuildModule(ctx, module.ConfigItem{ID: module.DerivedDailySummary})
|
||||
if err != nil {
|
||||
t.Fatalf("BuildModule() error = %v", err)
|
||||
}
|
||||
value := moduleValue[DerivedDailySummaryModule](t, output)
|
||||
|
||||
if value.HighTempF == nil || *value.HighTempF != 96 || value.LowTempF == nil || *value.LowTempF != 31 {
|
||||
t.Fatalf("daily temperatures = %#v/%#v, want fallback 96/31", value.HighTempF, value.LowTempF)
|
||||
}
|
||||
if value.DailyPrecipitationProbability == nil || *value.DailyPrecipitationProbability != 80 {
|
||||
t.Fatalf("DailyPrecipitationProbability = %#v, want hourly fallback 80", value.DailyPrecipitationProbability)
|
||||
}
|
||||
if len(value.DominantConditions) == 0 || !containsString(value.DominantConditions, "Thunderstorms with gusty wind") {
|
||||
t.Fatalf("DominantConditions = %#v, want fallback daypart conditions", value.DominantConditions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrecipTimingModuleHandlesRainyAndDryForecasts(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
ctx := derivedModuleContext(report.DailyToday)
|
||||
@@ -217,14 +247,26 @@ func derivedModuleContext(id report.ID) ModuleContext {
|
||||
}
|
||||
narrative := []weatherdata.ForecastPeriod{
|
||||
{
|
||||
Name: "Today",
|
||||
StartTime: mustParseModuleTime("2026-05-29T06:00:00-05:00"),
|
||||
EndTime: mustParseModuleTime("2026-05-29T18:00:00-05:00"),
|
||||
TextDescription: "Morning storms, then partly sunny.",
|
||||
TemperatureF: floatPtr(81),
|
||||
Name: "Today",
|
||||
StartTime: mustParseModuleTime("2026-05-29T06:00:00-05:00"),
|
||||
EndTime: mustParseModuleTime("2026-05-29T18:00:00-05:00"),
|
||||
IsDay: boolPtr(true),
|
||||
TextDescription: "Morning storms, then partly sunny.",
|
||||
TemperatureFMax: floatPtr(88),
|
||||
ProbabilityOfPrecipitationPercent: floatPtr(55),
|
||||
},
|
||||
{
|
||||
Name: "Tonight",
|
||||
StartTime: mustParseModuleTime("2026-05-29T18:00:00-05:00"),
|
||||
EndTime: mustParseModuleTime("2026-05-30T00:00:00-05:00"),
|
||||
IsDay: boolPtr(false),
|
||||
TextDescription: "Clouds linger tonight.",
|
||||
TemperatureFMin: floatPtr(64),
|
||||
ProbabilityOfPrecipitationPercent: floatPtr(30),
|
||||
},
|
||||
}
|
||||
summary.Dayparts[2].AlertOverlaps = []forecast.AlertOverlap{{Event: "Severe Thunderstorm Watch"}}
|
||||
summary.NarrativePeriods = append([]weatherdata.ForecastPeriod(nil), narrative...)
|
||||
return ModuleContext{
|
||||
Resolved: report.Resolved{
|
||||
Definition: definition,
|
||||
@@ -276,3 +318,16 @@ func derivedHour(start string, text string, precip float64, temperature float64,
|
||||
func floatPtr(value float64) *float64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
func boolPtr(value bool) *bool {
|
||||
return &value
|
||||
}
|
||||
|
||||
func containsString(values []string, want string) bool {
|
||||
for _, value := range values {
|
||||
if value == want {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user