190 lines
6.9 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|