package generatedtext import ( "strings" "testing" "gitea.maximumdirect.net/eric/weatherreporter/internal/report" ) func TestCatalogCompleteForGeneratedTextTemplateReports(t *testing.T) { for _, definition := range report.DefaultRegistry().All() { if definition.GenerationMode != report.GenerationModeGeneratedTextTemplate { continue } t.Run(string(definition.ID), func(t *testing.T) { handler, err := LookupDefinition(definition) if err != nil { t.Fatalf("LookupDefinition() error = %v", err) } if handler.SchemaID() != definition.GeneratedTextSchemaID { t.Fatalf("SchemaID() = %q, want %q", handler.SchemaID(), definition.GeneratedTextSchemaID) } if handler.TemplateID() != definition.TemplateID { t.Fatalf("TemplateID() = %q, want %q", handler.TemplateID(), definition.TemplateID) } if handler.validate == nil { t.Fatal("validator is nil") } if handler.renderContextBuilder == nil { t.Fatal("render-context builder is nil") } if schema, err := handler.Schema(); err != nil { t.Fatalf("Schema() error = %v", err) } else if len(schema) == 0 { t.Fatal("Schema() returned empty asset") } if template, err := handler.Template(); err != nil { t.Fatalf("Template() error = %v", err) } else if template == "" { t.Fatal("Template() returned empty asset") } }) } } func TestCatalogLookupRejectsUnsupportedSchemaAndTemplate(t *testing.T) { tests := []struct { name string definition report.Definition want []string }{ { name: "schema", definition: func() report.Definition { definition := report.DefaultRegistry().MustLookup(report.Hourly) definition.GeneratedTextSchemaID = "missing-schema" return definition }(), want: []string{`generated text schema "missing-schema"`, `report "hourly"`}, }, { name: "template", definition: func() report.Definition { definition := report.DefaultRegistry().MustLookup(report.Hourly) definition.TemplateID = "missing-template" return definition }(), want: []string{`report template "missing-template"`, `report "hourly"`}, }, { name: "combination", definition: func() report.Definition { definition := report.DefaultRegistry().MustLookup(report.Hourly) definition.TemplateID = "tomorrow" return definition }(), want: []string{`generated text schema "hourly"`, `report template "tomorrow"`, `report "hourly"`}, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { _, err := LookupDefinition(test.definition) if err == nil { t.Fatal("LookupDefinition() error = nil, want error") } for _, want := range test.want { if !strings.Contains(err.Error(), want) { t.Fatalf("LookupDefinition() error = %v, want %q", err, want) } } }) } } func TestCatalogLookupSupportsTodayDefinition(t *testing.T) { definition := report.Definition{ ID: report.Today, GenerationMode: report.GenerationModeGeneratedTextTemplate, GeneratedTextSchemaID: "today", TemplateID: "today", } handler, err := LookupDefinition(definition) if err != nil { t.Fatalf("LookupDefinition(today) error = %v", err) } if handler.SchemaID() != "today" || handler.TemplateID() != "today" { t.Fatalf("handler IDs = %q/%q, want today/today", handler.SchemaID(), handler.TemplateID()) } if schema, err := handler.Schema(); err != nil { t.Fatalf("Schema() error = %v", err) } else if len(schema) == 0 { t.Fatal("Schema() returned empty asset") } if template, err := handler.Template(); err != nil { t.Fatalf("Template() error = %v", err) } else if !strings.Contains(template, "# {{ .Report.Title }}") { t.Fatalf("Template() = %q, want Today template source", template) } } func TestCatalogValidationDispatchSupportsKnownSchemas(t *testing.T) { hourlyHandler, err := LookupDefinition(report.DefaultRegistry().MustLookup(report.Hourly)) if err != nil { t.Fatalf("LookupDefinition(hourly) error = %v", err) } hourly, normalized, err := hourlyHandler.Validate([]byte(`{ "summary": " Storm chances increase. ", "forecast_discussion": " A front will keep the region unsettled. " }`)) if err != nil { t.Fatalf("Validate(hourly) error = %v", err) } if _, ok := hourly.(Hourly); !ok { t.Fatalf("hourly generated text type = %T, want generatedtext.Hourly", hourly) } if !strings.Contains(string(normalized), `"summary":"Storm chances increase."`) { t.Fatalf("hourly normalized text = %s, want trimmed summary", normalized) } tomorrowHandler, err := LookupDefinition(report.DefaultRegistry().MustLookup(report.Tomorrow)) if err != nil { t.Fatalf("LookupDefinition(tomorrow) error = %v", err) } tomorrow, normalized, err := tomorrowHandler.Validate([]byte(`{ "summary": " Storms become more likely tomorrow. ", "forecast_discussion": [" A front will keep showers in the forecast. ", ""] }`)) if err != nil { t.Fatalf("Validate(tomorrow) error = %v", err) } if _, ok := tomorrow.(Tomorrow); !ok { t.Fatalf("tomorrow generated text type = %T, want generatedtext.Tomorrow", tomorrow) } if !strings.Contains(string(normalized), `"forecast_discussion":["A front will keep showers in the forecast."]`) { t.Fatalf("tomorrow normalized text = %s, want trimmed discussion paragraph", normalized) } todayHandler, err := LookupDefinition(report.Definition{ ID: report.Today, GenerationMode: report.GenerationModeGeneratedTextTemplate, GeneratedTextSchemaID: "today", TemplateID: "today", }) if err != nil { t.Fatalf("LookupDefinition(today) error = %v", err) } today, normalized, err := todayHandler.Validate([]byte(`{ "summary": " Showers are likely today. ", "forecast_discussion": [" A front will keep rain chances elevated. ", ""] }`)) if err != nil { t.Fatalf("Validate(today) error = %v", err) } if _, ok := today.(Today); !ok { t.Fatalf("today generated text type = %T, want generatedtext.Today", today) } if !strings.Contains(string(normalized), `"forecast_discussion":["A front will keep rain chances elevated."]`) { t.Fatalf("today normalized text = %s, want trimmed discussion paragraph", normalized) } } func TestCatalogBuildRenderContextRejectsMismatchedGeneratedText(t *testing.T) { hourlyHandler, err := LookupDefinition(report.DefaultRegistry().MustLookup(report.Hourly)) if err != nil { t.Fatalf("LookupDefinition(hourly) error = %v", err) } _, err = hourlyHandler.BuildRenderContext(testMetadata(), testSnapshot(t), testCollected(), testDerived(), Tomorrow{ Summary: "Storms become more likely tomorrow.", ForecastDiscussion: []string{"A front will keep showers in the forecast."}, }) if err == nil { t.Fatal("BuildRenderContext(hourly) error = nil, want type mismatch") } if !strings.Contains(err.Error(), `requires hourly generated text`) { t.Fatalf("BuildRenderContext(hourly) error = %v, want hourly generated text requirement", err) } tomorrowHandler, err := LookupDefinition(report.DefaultRegistry().MustLookup(report.Tomorrow)) if err != nil { t.Fatalf("LookupDefinition(tomorrow) error = %v", err) } _, err = tomorrowHandler.BuildRenderContext(testTomorrowMetadata(), testTomorrowSnapshot(t), testCollected(), testTomorrowDerived(), Hourly{ Summary: "Storm chances increase.", ForecastDiscussion: "A front will keep showers in the forecast.", }) if err == nil { t.Fatal("BuildRenderContext(tomorrow) error = nil, want type mismatch") } if !strings.Contains(err.Error(), `requires tomorrow generated text`) { t.Fatalf("BuildRenderContext(tomorrow) error = %v, want tomorrow generated text requirement", err) } todayHandler, err := LookupDefinition(report.Definition{ ID: report.Today, GenerationMode: report.GenerationModeGeneratedTextTemplate, GeneratedTextSchemaID: "today", TemplateID: "today", }) if err != nil { t.Fatalf("LookupDefinition(today) error = %v", err) } _, err = todayHandler.BuildRenderContext(testTodayMetadata(), testTodaySnapshot(t), testCollected(), testTodayDerived(), Tomorrow{ Summary: "Storms become more likely tomorrow.", ForecastDiscussion: []string{"A front will keep showers in the forecast."}, }) if err == nil { t.Fatal("BuildRenderContext(today) error = nil, want type mismatch") } if !strings.Contains(err.Error(), `requires today generated text`) { t.Fatalf("BuildRenderContext(today) error = %v, want today generated text requirement", err) } }