Files
RenewCMS/test/image_variants_hygiene_test.go
2026-10-08 02:33:32 +02:00

190 lines
6.9 KiB
Go

package test
import (
"bytes"
"go/parser"
"go/token"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
var variantUseCaseFiles = []string{
"ListVariants.go", "CreateVariant.go", "UpdateVariant.go", "SetVariantEnabled.go",
"DeleteVariant.go", "PurgeVariant.go", "ServeVariant.go", "variantCache.go",
"variantSettings.go", "variantSummary.go", "mediaRemover.go", "DeleteMedia.go", "MergeMedia.go",
}
var newVariantGoFiles = []string{
"internal/domain/image/variantDomain.go",
"internal/domain/image/variantRepositoryInterface.go",
"internal/domain/image/variantRequest.go",
"internal/domain/image/animatedGif.go",
"internal/infrastructure/imaging/variantEncoders.go",
"internal/infrastructure/imaging/variantGeometry.go",
"internal/infrastructure/imaging/variantRenderer.go",
"internal/infrastructure/config/imageVariantSettings.go",
"internal/infrastructure/persistence/models/imageVariantModel.go",
"internal/infrastructure/persistence/models/imageVariantFileModel.go",
"internal/infrastructure/persistence/mappers/imageVariantMapper.go",
"internal/infrastructure/persistence/repositories/imageVariantRepository.go",
"internal/infrastructure/persistence/repositories/imageVariantFileRepository.go",
"api/handlers/imagevariant/imageVariantHandler.go",
"api/handlers/staticimages/staticImagesHandler.go",
}
func importsOf(t *testing.T, relative string) []string {
t.Helper()
parsed, err := parser.ParseFile(token.NewFileSet(), "../"+relative, nil, parser.ImportsOnly)
if err != nil {
t.Fatalf("cannot parse %s: %v", relative, err)
}
imports := []string{}
for _, spec := range parsed.Imports {
imports = append(imports, strings.Trim(spec.Path.Value, `"`))
}
return imports
}
func isStandardLibrary(path string) bool {
return !strings.Contains(strings.Split(path, "/")[0], ".")
}
func TestImageVariantLayering(t *testing.T) {
t.Run("internal/domain/image imports only the stdlib and other domain packages", func(t *testing.T) {
files, _ := filepath.Glob("../internal/domain/image/*.go")
for _, file := range files {
for _, path := range importsOf(t, strings.TrimPrefix(filepath.ToSlash(file), "../")) {
if !isStandardLibrary(path) && !strings.HasPrefix(path, "RenewCMS/internal/domain/") {
t.Errorf("%s imports %s", file, path)
}
}
}
})
t.Run("internal/domain/audit still imports only the stdlib and domain packages", func(t *testing.T) {
files, _ := filepath.Glob("../internal/domain/audit/*.go")
for _, file := range files {
for _, path := range importsOf(t, strings.TrimPrefix(filepath.ToSlash(file), "../")) {
if !isStandardLibrary(path) && !strings.HasPrefix(path, "RenewCMS/internal/domain/") {
t.Errorf("%s imports %s", file, path)
}
}
}
})
t.Run("The variant use cases import no persistence, mailer, models, gorm, net/http, chi or api package", func(t *testing.T) {
forbidden := []string{"persistence", "mailer", "models", "gorm", "net/http", "go-chi", "RenewCMS/api"}
for _, name := range variantUseCaseFiles {
for _, path := range importsOf(t, "internal/infrastructure/useCases/"+name) {
for _, fragment := range forbidden {
if strings.Contains(path, fragment) {
t.Errorf("%s imports %s", name, path)
}
}
}
}
})
t.Run("The variant handlers import no persistence, mailer, models or gorm package", func(t *testing.T) {
for _, file := range []string{"api/handlers/imagevariant/imageVariantHandler.go", "api/handlers/staticimages/staticImagesHandler.go"} {
for _, path := range importsOf(t, file) {
for _, fragment := range []string{"persistence", "mailer", "models", "gorm"} {
if strings.Contains(path, fragment) {
t.Errorf("%s imports %s", file, path)
}
}
}
}
})
t.Run("The renderer is free of gorm and http", func(t *testing.T) {
for _, name := range []string{"variantEncoders.go", "variantGeometry.go", "variantRenderer.go"} {
for _, path := range importsOf(t, "internal/infrastructure/imaging/"+name) {
if strings.Contains(path, "gorm") || strings.Contains(path, "net/http") {
t.Errorf("%s imports %s", name, path)
}
}
}
})
t.Run("Only api/dependecyInjection.go constructs the variant repositories, the renderer and the use cases", func(t *testing.T) {
constructors := []string{"NewVariantRepository(", "NewVariantFileRepository(", "NewVariantRenderer(", "NewListVariantsUseCase(", "NewCreateVariantUseCase(", "NewUpdateVariantUseCase(", "NewSetVariantEnabledUseCase(", "NewDeleteVariantUseCase(", "NewPurgeVariantUseCase(", "NewServeVariantUseCase("}
for _, root := range []string{"../api", "../internal", "../cmd"} {
_ = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() || !strings.HasSuffix(path, ".go") || filepath.Base(path) == "dependecyInjection.go" {
return err
}
content, _ := os.ReadFile(path)
for _, constructor := range constructors {
if bytes.Contains(content, []byte(constructor)) && !definesConstructor(content, constructor) {
t.Errorf("%s calls %s", path, constructor)
}
}
return nil
})
}
})
t.Run("The new GORM models are registered in migrate.go", func(t *testing.T) {
migrate := readRepositoryFile(t, "internal/infrastructure/persistence/database/migrate.go")
if !strings.Contains(migrate, "&models.ImageVariant{}") || !strings.Contains(migrate, "&models.ImageVariantFile{}") {
t.Error("a variant model is missing from AutoMigrate")
}
})
}
func definesConstructor(content []byte, constructor string) bool {
return bytes.Contains(content, []byte("func "+constructor))
}
func TestImageVariantFilesHaveNoComments(t *testing.T) {
for _, relative := range newVariantGoFiles {
t.Run(relative, func(t *testing.T) {
parsed, err := parser.ParseFile(token.NewFileSet(), "../"+relative, nil, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
for _, group := range parsed.Comments {
for _, comment := range group.List {
if !strings.HasPrefix(comment.Text, "//go:") {
t.Errorf("comment %q", comment.Text)
}
}
}
})
}
}
func TestImageVariantBuildStaysCGOFree(t *testing.T) {
if testing.Short() {
t.Skip("builds the module")
}
environment := append(os.Environ(), "CGO_ENABLED=0")
t.Run("The module builds with CGO_ENABLED=0 and the nofrontend tag", func(t *testing.T) {
build := exec.Command("go", "build", "-tags", "nofrontend", "./...")
build.Dir, build.Env = "..", environment
if output, err := build.CombinedOutput(); err != nil {
t.Fatalf("build failed: %v\n%s", err, output)
}
})
t.Run("No dependency compiles cgo files", func(t *testing.T) {
list := exec.Command("go", "list", "-tags", "nofrontend", "-deps", "-f", "{{if .CgoFiles}}{{.ImportPath}}{{end}}", "./...")
list.Dir, list.Env = "..", environment
output, err := list.Output()
if err != nil {
t.Fatalf("go list failed: %v", err)
}
if strings.TrimSpace(string(output)) != "" {
t.Errorf("packages with cgo files: %s", output)
}
})
}