package event import ( "go/ast" "go/parser" "go/token" "os" "strings" "testing" ) // TestKnownTypes_ContainsAllTrackConstants is a build-time drift guard. // It walks event.go's Analytics const block via go/parser + go/ast and // asserts every `Track*` constant declared there appears in // event.KnownTypes. Self-deriving means: adding TrackNew requires // updating ONLY KnownTypes, not also the test. So the test cannot // itself drift. // // If you add a new Track* constant and accidentally forget // KnownTypes, this test fails. Update KnownTypes and re-run. func TestKnownTypes_ContainsAllTrackConstants(t *testing.T) { const srcPath = "event.go" raw, err := os.ReadFile(srcPath) if err != nil { t.Skipf("cannot read %q (running under go test in a different layout) — drift check deferred: %v", srcPath, err) } fset := token.NewFileSet() file, err := parser.ParseFile(fset, srcPath, string(raw), parser.ParseComments) if err != nil { t.Fatalf("parser.ParseFile failed: %v", err) } var trackConsts []Type ast.Inspect(file, func(n ast.Node) bool { gen, ok := n.(*ast.GenDecl) if !ok || gen.Tok != token.CONST { return true } for _, spec := range gen.Specs { vs, ok := spec.(*ast.ValueSpec) if !ok { continue } for i, name := range vs.Names { if !strings.HasPrefix(name.Name, "Track") { continue } if vs.Values == nil || i >= len(vs.Values) { continue } bl, ok := vs.Values[i].(*ast.BasicLit) if !ok || bl.Kind != token.STRING { continue } trackConsts = append(trackConsts, Type(strings.Trim(bl.Value, `""`))) } } return true }) if len(trackConsts) == 0 { t.Fatalf("AST scan did not find any Track* constants in event.go — check the AST walker or the file layout") } for _, c := range KnownTypes { found := false for _, tc := range trackConsts { if tc == c { found = true break } } if !found { t.Errorf("KnownTypes contains %q but the const block in event.go does NOT declare a Track* with that value", string(c)) } } for _, tc := range trackConsts { found := false for _, c := range KnownTypes { if c == tc { found = true break } } if !found { t.Errorf("event.go declares Track* = %q but KnownTypes is missing it — add it to KnownTypes and re-run", string(tc)) } } }