Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/gen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func (g *Generator) processFile(inputFile, inputRoot string) error {
}

if shouldSkipFile(inputFile) {
fmt.Printf("Skipping generated file: %s\n", inputFile)
fmt.Printf("Skipping file: %s\n", inputFile)
return nil
}

Expand Down
80 changes: 80 additions & 0 deletions internal/gen/generator_support_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package gen

import (
"io/fs"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)

// generateFromSources writes files into a throwaway module, runs the generator over it and
// returns the concatenated generated code. Keys are file names relative to the module root.
func generateFromSources(t *testing.T, files map[string]string) string {
t.Helper()

dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module example.com/sample\n\ngo 1.21\n"), 0o644); err != nil {
t.Fatalf("write go.mod: %v", err)
}
for name, content := range files {
path := filepath.Join(dir, name)
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatalf("create directory for %s: %v", name, err)
}
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatalf("write %s: %v", name, err)
}
}

out := filepath.Join(dir, "out")
g := &Generator{Files: map[string]*File{}, outPath: out}
if err := g.Process(dir); err != nil {
t.Fatalf("Process: %v", err)
}
if err := g.Gen(); err != nil {
t.Fatalf("Gen: %v", err)
}
return readGeneratedTree(t, out)
}

// readGeneratedTree concatenates every generated file under dir, the nested packages included.
// readAllGeneratedGoFiles reads the top level only, which is enough for a fixture of one package
// but silently drops the output of one that spans several.
func readGeneratedTree(t *testing.T, dir string) string {
t.Helper()

var b strings.Builder
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() || !strings.HasSuffix(path, ".go") {
return nil
}
content, err := os.ReadFile(path)
if err != nil {
return err
}
b.WriteString(string(content))
b.WriteString("\n\n")

return nil
})
if err != nil {
t.Fatalf("read generated tree %s: %v", dir, err)
}
if b.Len() == 0 {
t.Fatalf("no .go files under %s", dir)
}

return b.String()
}

// containsField reports whether the generated code declares a helper named name with the given
// type, tolerating the column alignment gofmt applies to struct fields.
func containsField(content, name, typ string) bool {
re := regexp.MustCompile(`(?m)^\s*` + regexp.QuoteMeta(name) + `\s+` + regexp.QuoteMeta(typ) + `\s*$`)
return re.MatchString(content)
}
25 changes: 25 additions & 0 deletions internal/gen/skip_test_files_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gen

import (
"strings"
"testing"
)

func TestProcessSkipsTestFiles(t *testing.T) {
content := generateFromSources(t, map[string]string{
"model.go": "package sample\n\ntype Article struct {\n\tID uint\n\tTitle string\n}\n",
"model_test.go": "package sample\n\ntype Fixture struct {\n\tID uint\n}\n",
})

if !strings.Contains(content, "var Article = struct") {
t.Fatalf("expected helpers for Article, got:\n%s", content)
}
if strings.Contains(content, "var Fixture = struct") {
t.Fatalf("test-only type Fixture must not get a helper, got:\n%s", content)
}
// And the broad form as well: a leak could surface as a field type rather than as a helper
// block of its own, which a check for the block alone would not see.
if strings.Contains(content, "Fixture") {
t.Fatalf("no trace of a test-only type may reach the generated package, got:\n%s", content)
}
}
6 changes: 4 additions & 2 deletions internal/gen/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,11 @@ func mergeImports(dst *[]Import, src []Import) {
}
}

// shouldSkipFile checks if a file contains the generated code header and should be skipped
// shouldSkipFile reports whether a file is not an input for generation: anything that is not Go
// source, test files (their types exist for tests only and would leak helpers into the output),
// and files the generator wrote itself.
func shouldSkipFile(filePath string) bool {
if !strings.HasSuffix(filePath, ".go") {
if !strings.HasSuffix(filePath, ".go") || strings.HasSuffix(filePath, "_test.go") {
return true
Comment on lines +178 to 183
}

Expand Down
Loading