Refactor the template variable framework
This commit is contained in:
@@ -11,7 +11,7 @@ func TestTemplateLookup(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Template() error = %v", err)
|
||||
}
|
||||
for _, want := range []string{"# {{ .ReportTitle }}", "## Summary", "## Hourly Forecast", "## Weather Story"} {
|
||||
for _, want := range []string{"# {{ .Report.Title }}", "## Summary", "## Hourly Forecast", "## Weather Story"} {
|
||||
if !strings.Contains(source, want) {
|
||||
t.Fatalf("template missing %q:\n%s", want, source)
|
||||
}
|
||||
@@ -54,29 +54,58 @@ func TestSchemaLookup(t *testing.T) {
|
||||
|
||||
func TestRenderHourly(t *testing.T) {
|
||||
rendered, err := Render("hourly", testRenderContext{
|
||||
ReportTitle: "Hourly Report",
|
||||
LocationName: "Brentwood",
|
||||
ValidPeriod: "May 29, 8:30 AM to 2:30 PM",
|
||||
GeneratedAt: "May 29, 8:30 AM",
|
||||
CurrentConditions: "74 F, light south wind.",
|
||||
PrecipitationTiming: "Showers are most likely late morning.",
|
||||
WeatherStory: "Morning storms remain the main story.",
|
||||
Report: testReportContext{
|
||||
Title: "Hourly Report",
|
||||
LocationName: "Brentwood",
|
||||
ValidPeriodLabel: "May 29, 8:30 AM to 2:30 PM",
|
||||
GeneratedAtLabel: "May 29, 8:30 AM",
|
||||
},
|
||||
GeneratedText: testGeneratedText{
|
||||
Summary: "Storm chances increase through late morning.",
|
||||
Timing: "The main window is 10 AM to noon.",
|
||||
Impacts: "Brief downpours may slow travel.",
|
||||
Confidence: "Medium confidence in timing.",
|
||||
},
|
||||
HourlyForecast: []testHourlyRow{
|
||||
{Time: "9 AM", Summary: "Cloudy", Temperature: "74 F", Precipitation: "30% showers", Wind: "S 8 mph"},
|
||||
{Time: "10 AM", Summary: "Showers", Temperature: "75 F", Precipitation: "70% showers", Wind: "S 10 mph"},
|
||||
},
|
||||
Alerts: []string{"Flood Watch until 2:30 PM"},
|
||||
SPCOutlooks: []string{"Slight Risk through afternoon"},
|
||||
SPCDiscussions: []string{"Strong storms may develop late morning."},
|
||||
ForecastDiscussion: testForecastDiscussion{
|
||||
KeyMessages: []string{"Storms are most likely late morning."},
|
||||
ShortTerm: "Short-term discussion favors increasing rain coverage.",
|
||||
Modules: testModules{
|
||||
CurrentConditions: &testCurrentConditions{
|
||||
ConditionText: "Partly cloudy",
|
||||
TemperatureF: floatPtr(74),
|
||||
ApparentTemperatureF: floatPtr(76),
|
||||
RelativeHumidityPercent: floatPtr(71),
|
||||
WindDirection: "S",
|
||||
WindSpeedMph: floatPtr(8),
|
||||
},
|
||||
HourlyForecast: &testHourlyForecast{
|
||||
Periods: []testHourlyPeriod{
|
||||
{PeriodBegins: "9 AM", TextDescription: "Cloudy", TemperatureF: floatPtr(74), ProbabilityOfPrecipitationPercent: floatPtr(30), WindDirection: "S", WindSpeedMph: floatPtr(8)},
|
||||
{PeriodBegins: "10 AM", TextDescription: "Showers", TemperatureF: floatPtr(75), ProbabilityOfPrecipitationPercent: floatPtr(70), WindDirection: "S", WindSpeedMph: floatPtr(10)},
|
||||
},
|
||||
},
|
||||
PrecipTiming: &testPrecipTiming{
|
||||
MaxPopPercent: intPtr(70),
|
||||
MaxPopTime: "10 AM",
|
||||
PrecipitationWindows: []testPrecipWindow{
|
||||
{PeriodBegins: "10 AM", PeriodEnds: "12 PM", MaxPopPercent: intPtr(70), MaxPopTime: "10 AM"},
|
||||
},
|
||||
},
|
||||
AlertDigest: &testAlertDigest{
|
||||
Relevant: []testAlert{{Event: "Flood Watch", Headline: "Flood Watch until 2:30 PM", Severity: "Moderate"}},
|
||||
},
|
||||
SPCConvectiveOutlooks: &testSPCOutlooks{
|
||||
Outlooks: []testSPCOutlook{{LabelText: "Slight Risk", PeriodBegins: "8 AM", PeriodEnds: "2 PM"}},
|
||||
},
|
||||
SPCConvectiveDiscussion: &testSPCDiscussion{
|
||||
Discussions: []testSPCDiscussionRecord{{Summary: "Strong storms may develop late morning."}},
|
||||
},
|
||||
AreaForecastDiscussion: &testForecastDiscussion{
|
||||
KeyMessages: []string{"Storms are most likely late morning."},
|
||||
ShortTerm: "Short-term discussion favors increasing rain coverage.",
|
||||
},
|
||||
WeatherStory: &testWeatherStory{
|
||||
Available: true,
|
||||
Title: "Morning storms",
|
||||
Description: "Morning storms remain the main story.",
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -88,8 +117,8 @@ func TestRenderHourly(t *testing.T) {
|
||||
"Valid: May 29, 8:30 AM to 2:30 PM",
|
||||
"Storm chances increase through late morning.",
|
||||
"## Confidence",
|
||||
"- 10 AM: Showers; 75 F; 70% showers; S 10 mph",
|
||||
"- Flood Watch until 2:30 PM",
|
||||
"- 10 AM: Showers; 75 F; 70% precipitation; wind S 10 mph",
|
||||
"- Flood Watch: Flood Watch until 2:30 PM (Moderate)",
|
||||
"Short-term discussion favors increasing rain coverage.",
|
||||
} {
|
||||
if !strings.Contains(text, want) {
|
||||
@@ -126,7 +155,7 @@ func TestUnknownAssetsReturnActionableErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenderFailsForMissingContextFields(t *testing.T) {
|
||||
_, err := Render("hourly", map[string]any{"ReportTitle": "Hourly Report"})
|
||||
_, err := Render("hourly", map[string]any{"Report": map[string]any{"Title": "Hourly Report"}})
|
||||
if err == nil {
|
||||
t.Fatal("Render() error = nil, want missing field error")
|
||||
}
|
||||
@@ -136,19 +165,16 @@ func TestRenderFailsForMissingContextFields(t *testing.T) {
|
||||
}
|
||||
|
||||
type testRenderContext struct {
|
||||
ReportTitle string
|
||||
LocationName string
|
||||
ValidPeriod string
|
||||
GeneratedAt string
|
||||
CurrentConditions string
|
||||
PrecipitationTiming string
|
||||
WeatherStory string
|
||||
GeneratedText testGeneratedText
|
||||
HourlyForecast []testHourlyRow
|
||||
Alerts []string
|
||||
SPCOutlooks []string
|
||||
SPCDiscussions []string
|
||||
ForecastDiscussion testForecastDiscussion
|
||||
Report testReportContext
|
||||
GeneratedText testGeneratedText
|
||||
Modules testModules
|
||||
}
|
||||
|
||||
type testReportContext struct {
|
||||
Title string
|
||||
LocationName string
|
||||
ValidPeriodLabel string
|
||||
GeneratedAtLabel string
|
||||
}
|
||||
|
||||
type testGeneratedText struct {
|
||||
@@ -158,12 +184,76 @@ type testGeneratedText struct {
|
||||
Confidence string
|
||||
}
|
||||
|
||||
type testHourlyRow struct {
|
||||
Time string
|
||||
Summary string
|
||||
Temperature string
|
||||
Precipitation string
|
||||
Wind string
|
||||
type testModules struct {
|
||||
CurrentConditions *testCurrentConditions
|
||||
HourlyForecast *testHourlyForecast
|
||||
PrecipTiming *testPrecipTiming
|
||||
AlertDigest *testAlertDigest
|
||||
SPCConvectiveOutlooks *testSPCOutlooks
|
||||
AreaForecastDiscussion *testForecastDiscussion
|
||||
SPCConvectiveDiscussion *testSPCDiscussion
|
||||
WeatherStory *testWeatherStory
|
||||
}
|
||||
|
||||
type testCurrentConditions struct {
|
||||
ConditionText string
|
||||
TemperatureF *float64
|
||||
ApparentTemperatureF *float64
|
||||
RelativeHumidityPercent *float64
|
||||
WindSpeedMph *float64
|
||||
WindDirection string
|
||||
}
|
||||
|
||||
type testHourlyForecast struct {
|
||||
Periods []testHourlyPeriod
|
||||
}
|
||||
|
||||
type testHourlyPeriod struct {
|
||||
PeriodBegins string
|
||||
Name string
|
||||
TextDescription string
|
||||
TemperatureF *float64
|
||||
WindSpeedMph *float64
|
||||
WindGustMph *float64
|
||||
WindDirection string
|
||||
ProbabilityOfPrecipitationPercent *float64
|
||||
}
|
||||
|
||||
type testPrecipTiming struct {
|
||||
MaxPopPercent *int
|
||||
MaxPopTime string
|
||||
PrecipitationWindows []testPrecipWindow
|
||||
ThunderMentioned bool
|
||||
}
|
||||
|
||||
type testPrecipWindow struct {
|
||||
PeriodBegins string
|
||||
PeriodEnds string
|
||||
MaxPopPercent *int
|
||||
MaxPopTime string
|
||||
}
|
||||
|
||||
type testAlertDigest struct {
|
||||
Missing bool
|
||||
Relevant []testAlert
|
||||
}
|
||||
|
||||
type testAlert struct {
|
||||
Event string
|
||||
Headline string
|
||||
Severity string
|
||||
}
|
||||
|
||||
type testSPCOutlooks struct {
|
||||
Outlooks []testSPCOutlook
|
||||
}
|
||||
|
||||
type testSPCOutlook struct {
|
||||
Label string
|
||||
LabelText string
|
||||
OutlookType string
|
||||
PeriodBegins string
|
||||
PeriodEnds string
|
||||
}
|
||||
|
||||
type testForecastDiscussion struct {
|
||||
@@ -171,6 +261,30 @@ type testForecastDiscussion struct {
|
||||
ShortTerm string
|
||||
}
|
||||
|
||||
type testSPCDiscussion struct {
|
||||
Discussions []testSPCDiscussionRecord
|
||||
}
|
||||
|
||||
type testSPCDiscussionRecord struct {
|
||||
Headline string
|
||||
Summary string
|
||||
Discussion string
|
||||
}
|
||||
|
||||
type testWeatherStory struct {
|
||||
Available bool
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
func floatPtr(value float64) *float64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
func intPtr(value int) *int {
|
||||
return &value
|
||||
}
|
||||
|
||||
func assertOrderedText(t *testing.T, text string, ordered []string) {
|
||||
t.Helper()
|
||||
previousIndex := -1
|
||||
|
||||
Reference in New Issue
Block a user