Add embedded hourly report template assets
This commit is contained in:
157
internal/reporttemplate/reporttemplate_test.go
Normal file
157
internal/reporttemplate/reporttemplate_test.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package reporttemplate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTemplateLookup(t *testing.T) {
|
||||
source, err := Template("hourly")
|
||||
if err != nil {
|
||||
t.Fatalf("Template() error = %v", err)
|
||||
}
|
||||
for _, want := range []string{"# {{ .ReportTitle }}", "## Summary", "## Hourly Forecast", "## Weather Story"} {
|
||||
if !strings.Contains(source, want) {
|
||||
t.Fatalf("template missing %q:\n%s", want, source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchemaLookup(t *testing.T) {
|
||||
data, err := Schema("hourly")
|
||||
if err != nil {
|
||||
t.Fatalf("Schema() error = %v", err)
|
||||
}
|
||||
var schema struct {
|
||||
Type string `json:"type"`
|
||||
AdditionalProperties bool `json:"additionalProperties"`
|
||||
Required []string `json:"required"`
|
||||
Properties map[string]any `json:"properties"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &schema); err != nil {
|
||||
t.Fatalf("schema is invalid JSON: %v", err)
|
||||
}
|
||||
if schema.Type != "object" {
|
||||
t.Fatalf("schema type = %q, want object", schema.Type)
|
||||
}
|
||||
if schema.AdditionalProperties {
|
||||
t.Fatal("additionalProperties = true, want false")
|
||||
}
|
||||
if strings.Join(schema.Required, ",") != "summary,timing,impacts" {
|
||||
t.Fatalf("required = %#v, want summary/timing/impacts", schema.Required)
|
||||
}
|
||||
for _, field := range []string{"summary", "timing", "impacts", "confidence"} {
|
||||
property, ok := schema.Properties[field].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("schema property %q missing or invalid", field)
|
||||
}
|
||||
if property["type"] != "string" {
|
||||
t.Fatalf("schema property %q type = %v, want string", field, property["type"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.",
|
||||
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.",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Render() error = %v", err)
|
||||
}
|
||||
text := string(rendered)
|
||||
for _, want := range []string{
|
||||
"# Hourly Report",
|
||||
"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",
|
||||
"Short-term discussion favors increasing rain coverage.",
|
||||
} {
|
||||
if !strings.Contains(text, want) {
|
||||
t.Fatalf("rendered template missing %q:\n%s", want, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownAssetsReturnActionableErrors(t *testing.T) {
|
||||
if _, err := Template("daily"); err == nil || !strings.Contains(err.Error(), `unknown report template "daily"`) {
|
||||
t.Fatalf("Template() error = %v, want unknown template", err)
|
||||
}
|
||||
if _, err := Schema("daily"); err == nil || !strings.Contains(err.Error(), `unknown generated text schema "daily"`) {
|
||||
t.Fatalf("Schema() error = %v, want unknown schema", err)
|
||||
}
|
||||
if _, err := Render("daily", testRenderContext{}); err == nil || !strings.Contains(err.Error(), `unknown report template "daily"`) {
|
||||
t.Fatalf("Render() error = %v, want unknown template", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderFailsForMissingContextFields(t *testing.T) {
|
||||
_, err := Render("hourly", map[string]any{"ReportTitle": "Hourly Report"})
|
||||
if err == nil {
|
||||
t.Fatal("Render() error = nil, want missing field error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), `render report template "hourly"`) {
|
||||
t.Fatalf("Render() error = %v, want render context", err)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type testGeneratedText struct {
|
||||
Summary string
|
||||
Timing string
|
||||
Impacts string
|
||||
Confidence string
|
||||
}
|
||||
|
||||
type testHourlyRow struct {
|
||||
Time string
|
||||
Summary string
|
||||
Temperature string
|
||||
Precipitation string
|
||||
Wind string
|
||||
}
|
||||
|
||||
type testForecastDiscussion struct {
|
||||
KeyMessages []string
|
||||
ShortTerm string
|
||||
}
|
||||
Reference in New Issue
Block a user