158 lines
5.1 KiB
Go
158 lines
5.1 KiB
Go
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
|
|
}
|