Add near-term module composition
This commit is contained in:
@@ -97,6 +97,21 @@ func TestHourlyForecastModuleRejectsUnsupportedReports(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHourlyForecastModuleBuildsForNearTerm(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
ctx := testModuleContext()
|
||||
ctx.Resolved.Definition = report.DefaultRegistry().MustLookup(report.NearTerm)
|
||||
|
||||
output, err := registry.BuildModule(ctx, module.ConfigItem{ID: module.HourlyForecast})
|
||||
if err != nil {
|
||||
t.Fatalf("BuildModule() error = %v", err)
|
||||
}
|
||||
value := moduleValue[HourlyForecastModule](t, output)
|
||||
if len(value.Periods) != 1 || value.Periods[0].TextDescription != "Showers likely." {
|
||||
t.Fatalf("HourlyForecast = %#v, want near-term hourly period", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNarrativeForecastModuleUsesValidPeriodNarrativePeriods(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
ctx := testModuleContext()
|
||||
@@ -320,6 +335,34 @@ func TestAreaForecastDiscussionModuleCanSelectSections(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAreaForecastDiscussionModuleUsesNearTermDefaultSections(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
ctx := testModuleContext()
|
||||
ctx.Resolved.Definition = report.DefaultRegistry().MustLookup(report.NearTerm)
|
||||
var item module.ConfigItem
|
||||
for _, candidate := range ctx.Resolved.Definition.Modules {
|
||||
if candidate.ID == module.AreaForecastDiscussion {
|
||||
item = candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
if item.ID == "" {
|
||||
t.Fatal("near-term default modules missing area_forecast_discussion")
|
||||
}
|
||||
|
||||
output, err := registry.BuildModule(ctx, item)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildModule() error = %v", err)
|
||||
}
|
||||
afd := moduleValue[AreaForecastDiscussionModule](t, output)
|
||||
if len(afd.KeyMessages) != 1 || afd.ShortTerm != "Showers increase this afternoon." {
|
||||
t.Fatalf("AFD = %#v, want key messages and short term", afd)
|
||||
}
|
||||
if afd.Product != "" || afd.LongTerm != "" {
|
||||
t.Fatalf("AFD = %#v, want product and long term omitted", afd)
|
||||
}
|
||||
}
|
||||
|
||||
func testModuleContext() ModuleContext {
|
||||
generatedAt := mustParseModuleTime("2026-05-29T08:00:00-05:00")
|
||||
definition := report.DefaultRegistry().MustLookup(report.DailyToday)
|
||||
|
||||
@@ -249,7 +249,7 @@ func (d ModuleDefinition) ValidateOptions(options any) error {
|
||||
}
|
||||
|
||||
func defaultModuleDefinitions() []ModuleDefinition {
|
||||
allReports := []report.ID{report.DailyToday, report.DailyTomorrow, report.ThreeDay, report.Weekend, report.Storm}
|
||||
allReports := []report.ID{report.DailyToday, report.DailyTomorrow, report.NearTerm, report.ThreeDay, report.Weekend, report.Storm}
|
||||
daypartReports := []report.ID{report.DailyToday, report.DailyTomorrow, report.ThreeDay, report.Weekend}
|
||||
return []ModuleDefinition{
|
||||
{
|
||||
@@ -286,7 +286,7 @@ func defaultModuleDefinitions() []ModuleDefinition {
|
||||
DefaultOptions: module.HourlyForecastOptions{},
|
||||
RequiredCollected: []module.FactRequirement{module.CollectedHourlyForecast},
|
||||
RequiredDerived: []module.FactRequirement{module.RequiresDerivedHourlyPeriods},
|
||||
SupportedReports: []report.ID{report.DailyToday, report.DailyTomorrow},
|
||||
SupportedReports: []report.ID{report.DailyToday, report.DailyTomorrow, report.NearTerm},
|
||||
MissingData: module.MissingDataOmit,
|
||||
Builder: buildHourlyForecastModule,
|
||||
},
|
||||
|
||||
@@ -32,9 +32,6 @@ func TestDefaultReportModulesBuildSnapshots(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
for _, definition := range report.DefaultRegistry().All() {
|
||||
t.Run(string(definition.ID), func(t *testing.T) {
|
||||
if len(definition.Modules) == 0 {
|
||||
return
|
||||
}
|
||||
ctx := derivedModuleContext(definition.ID)
|
||||
var outputs []module.Output
|
||||
for _, item := range definition.Modules {
|
||||
@@ -57,6 +54,27 @@ func TestDefaultReportModulesBuildSnapshots(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNearTermDefaultModuleOptions(t *testing.T) {
|
||||
definition := report.DefaultRegistry().MustLookup(report.NearTerm)
|
||||
var found bool
|
||||
for _, item := range definition.Modules {
|
||||
if item.ID != module.AreaForecastDiscussion {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
options, ok := item.Options.(module.AreaForecastDiscussionOptions)
|
||||
if !ok {
|
||||
t.Fatalf("AFD options type = %T, want AreaForecastDiscussionOptions", item.Options)
|
||||
}
|
||||
if strings.Join(options.Sections, ",") != "key_messages,short_term" {
|
||||
t.Fatalf("AFD sections = %#v, want key messages and short term", options.Sections)
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("near-term default modules missing area_forecast_discussion")
|
||||
}
|
||||
}
|
||||
|
||||
func TestModuleRegistryRejectsUnknownModule(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
err := registry.ValidateComposition(report.DailyToday, []module.ConfigItem{{ID: module.ID("unknown")}})
|
||||
@@ -94,6 +112,24 @@ func TestModuleRegistryRejectsIncompatibleReports(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestModuleRegistryRejectsNearTermIncompatibleModules(t *testing.T) {
|
||||
registry := MustDefaultModuleRegistry()
|
||||
for _, id := range []module.ID{
|
||||
module.NarrativeForecast,
|
||||
module.DerivedDailySummary,
|
||||
module.DerivedDaypartSummaries,
|
||||
module.OutdoorWindows,
|
||||
module.TomorrowPlanning,
|
||||
} {
|
||||
t.Run(string(id), func(t *testing.T) {
|
||||
err := registry.ValidateComposition(report.NearTerm, []module.ConfigItem{{ID: id}})
|
||||
if err == nil || !strings.Contains(err.Error(), `not compatible with report "near_term"`) {
|
||||
t.Fatalf("ValidateComposition() error = %v, want incompatible near-term module", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestModuleRegistryRejectsDefinitionsWithoutBuilders(t *testing.T) {
|
||||
_, err := NewModuleRegistry([]ModuleDefinition{
|
||||
{ID: module.Metadata, StanzaName: "metadata", DefaultOptions: module.MetadataOptions{}},
|
||||
|
||||
@@ -25,7 +25,22 @@ func nearTermDefinition() Definition {
|
||||
}
|
||||
|
||||
func nearTermModules() []module.ConfigItem {
|
||||
return nil
|
||||
return []module.ConfigItem{
|
||||
{ID: module.Metadata},
|
||||
{ID: module.CurrentConditions},
|
||||
{ID: module.HourlyForecast},
|
||||
{ID: module.PrecipTiming},
|
||||
{ID: module.AlertDigest},
|
||||
{ID: module.SPCConvectiveOutlooks},
|
||||
{
|
||||
ID: module.AreaForecastDiscussion,
|
||||
Options: module.AreaForecastDiscussionOptions{
|
||||
Sections: []string{"key_messages", "short_term"},
|
||||
},
|
||||
},
|
||||
{ID: module.SPCConvectiveDiscussion},
|
||||
{ID: module.WeatherStory},
|
||||
}
|
||||
}
|
||||
|
||||
func resolveNearTerm(req ResolveRequest) (timeutil.Period, error) {
|
||||
|
||||
@@ -384,8 +384,18 @@ func TestRegistryDefinitionsDeclareDefaultModules(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
id: NearTerm,
|
||||
want: []module.ID{},
|
||||
id: NearTerm,
|
||||
want: []module.ID{
|
||||
module.Metadata,
|
||||
module.CurrentConditions,
|
||||
module.HourlyForecast,
|
||||
module.PrecipTiming,
|
||||
module.AlertDigest,
|
||||
module.SPCConvectiveOutlooks,
|
||||
module.AreaForecastDiscussion,
|
||||
module.SPCConvectiveDiscussion,
|
||||
module.WeatherStory,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: ThreeDay,
|
||||
|
||||
Reference in New Issue
Block a user