From 985468c1b9a88305f26decb687f8a6af30f5afc1 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Thu, 11 Jun 2026 02:18:15 +0000 Subject: [PATCH] Add documentation identifier consistency tests --- cmd/weatherfeeder/main_test.go | 4 ++ internal/sources/docs_test.go | 32 ++++++++++++++++ standards/docs_test.go | 69 ++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 internal/sources/docs_test.go create mode 100644 standards/docs_test.go diff --git a/cmd/weatherfeeder/main_test.go b/cmd/weatherfeeder/main_test.go index 4508d42..46dc27c 100644 --- a/cmd/weatherfeeder/main_test.go +++ b/cmd/weatherfeeder/main_test.go @@ -112,6 +112,10 @@ func TestMaintainedConfigExamplesLoad(t *testing.T) { func assertConfigSourcesBuildSchedulerJobs(t *testing.T, cfg *config.Config) { t.Helper() + if len(cfg.Sources) == 0 { + t.Fatalf("config has no sources") + } + reg := fksources.NewRegistry() wfsources.RegisterBuiltins(reg) diff --git a/internal/sources/docs_test.go b/internal/sources/docs_test.go new file mode 100644 index 0000000..cfb2dc7 --- /dev/null +++ b/internal/sources/docs_test.go @@ -0,0 +1,32 @@ +package sources + +import ( + "os" + "strings" + "testing" +) + +func TestDocumentedRegisteredSourceDrivers(t *testing.T) { + docs := map[string]string{ + "docs/config.md": readDoc(t, "../../docs/config.md"), + "docs/internal/sources.md": readDoc(t, "../../docs/internal/sources.md"), + } + + for _, reg := range pollDriverRegistrations { + for path, doc := range docs { + if !strings.Contains(doc, reg.driver) { + t.Fatalf("%s missing source driver %q", path, reg.driver) + } + } + } +} + +func readDoc(t *testing.T, path string) string { + t.Helper() + + raw, err := os.ReadFile(path) + if err != nil { + t.Fatalf("ReadFile(%s) error = %v", path, err) + } + return string(raw) +} diff --git a/standards/docs_test.go b/standards/docs_test.go new file mode 100644 index 0000000..88ddf06 --- /dev/null +++ b/standards/docs_test.go @@ -0,0 +1,69 @@ +package standards + +import ( + "go/ast" + "go/parser" + "go/token" + "os" + "strconv" + "strings" + "testing" +) + +func TestDocumentedEventSchemas(t *testing.T) { + raw, err := os.ReadFile("../docs/integrations/events.md") + if err != nil { + t.Fatalf("ReadFile(events.md) error = %v", err) + } + doc := string(raw) + + schemas := schemaConstants(t) + for _, schema := range schemas { + if !strings.Contains(doc, schema) { + t.Fatalf("docs/integrations/events.md missing schema %q", schema) + } + } +} + +func schemaConstants(t *testing.T) []string { + t.Helper() + + file, err := parser.ParseFile(token.NewFileSet(), "schema.go", nil, 0) + if err != nil { + t.Fatalf("ParseFile(schema.go) error = %v", err) + } + + var out []string + ast.Inspect(file, func(n ast.Node) bool { + valueSpec, ok := n.(*ast.ValueSpec) + if !ok { + return true + } + for i, name := range valueSpec.Names { + if !strings.HasPrefix(name.Name, "Schema") || schemaConstantNotInCurrentContract(name.Name) { + continue + } + if i >= len(valueSpec.Values) { + t.Fatalf("schema constant %s has no explicit value", name.Name) + } + lit, ok := valueSpec.Values[i].(*ast.BasicLit) + if !ok || lit.Kind != token.STRING { + t.Fatalf("schema constant %s is not a string literal", name.Name) + } + schema, err := strconv.Unquote(lit.Value) + if err != nil { + t.Fatalf("schema constant %s value is not a quoted string: %v", name.Name, err) + } + out = append(out, schema) + } + return true + }) + if len(out) == 0 { + t.Fatalf("no schema constants found") + } + return out +} + +func schemaConstantNotInCurrentContract(name string) bool { + return name == "SchemaRawOpenWeatherHourlyForecastV1" +}