From f82b1e9dcb7e934c6466ebf18d10ffed77443dfe Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 26 Mar 2026 11:29:56 +0000 Subject: [PATCH] test(conventions): enforce AX review rules Co-Authored-By: Virgil --- conventions_test.go | 89 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 conventions_test.go diff --git a/conventions_test.go b/conventions_test.go new file mode 100644 index 0000000..94ff9f8 --- /dev/null +++ b/conventions_test.go @@ -0,0 +1,89 @@ +package store + +import ( + "go/ast" + "go/parser" + "go/token" + "os" + "path/filepath" + "slices" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRepoConventions_Good_BannedImports(t *testing.T) { + files := repoGoFiles(t, func(name string) bool { + return strings.HasSuffix(name, ".go") + }) + + var banned []string + for _, path := range files { + file := parseGoFile(t, path) + for _, spec := range file.Imports { + importPath := strings.Trim(spec.Path.Value, `"`) + if strings.HasPrefix(importPath, "forge.lthn.ai/") { + banned = append(banned, path+": "+importPath) + } + } + } + + slices.Sort(banned) + assert.Empty(t, banned, "legacy forge.lthn.ai imports are banned") +} + +func TestRepoConventions_Good_TestNaming(t *testing.T) { + files := repoGoFiles(t, func(name string) bool { + return strings.HasSuffix(name, "_test.go") + }) + + var invalid []string + for _, path := range files { + file := parseGoFile(t, path) + for _, decl := range file.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Recv != nil { + continue + } + name := fn.Name.Name + if !strings.HasPrefix(name, "Test") || name == "TestMain" { + continue + } + if strings.Contains(name, "_Good") || strings.Contains(name, "_Bad") || strings.Contains(name, "_Ugly") { + continue + } + invalid = append(invalid, path+": "+name) + } + } + + slices.Sort(invalid) + assert.Empty(t, invalid, "top-level tests must include _Good, _Bad, or _Ugly in the name") +} + +func repoGoFiles(t *testing.T, keep func(name string) bool) []string { + t.Helper() + + entries, err := os.ReadDir(".") + require.NoError(t, err) + + var files []string + for _, entry := range entries { + if entry.IsDir() || !keep(entry.Name()) { + continue + } + files = append(files, filepath.Clean(entry.Name())) + } + + slices.Sort(files) + return files +} + +func parseGoFile(t *testing.T, path string) *ast.File { + t.Helper() + + file, err := parser.ParseFile(token.NewFileSet(), path, nil, 0) + require.NoError(t, err) + return file +}