package test import ( domain "RenewCMS/internal/domain/image" persistence "RenewCMS/internal/infrastructure/persistence/repositories" "errors" "strings" "testing" ) func TestOutputGeometry(t *testing.T) { width := func(value int) *int { return &value } rows := []struct { name string sw, sh int settings domain.VariantSettings wantW, wantH int }{ {"cover with one side", 4032, 3024, domain.VariantSettings{Width: width(800), Fit: domain.FitCover}, 800, 600}, {"cover with both sides keeps the box ratio", 4032, 3024, domain.VariantSettings{Width: width(1000), Height: width(1000), Fit: domain.FitCover}, 1000, 1000}, {"cover shrinks the box to fit the source", 300, 200, domain.VariantSettings{Width: width(400), Height: width(300), Fit: domain.FitCover}, 267, 200}, {"contain is the box", 300, 200, domain.VariantSettings{Width: width(400), Height: width(300), Fit: domain.FitContain}, 400, 300}, {"inside never upscales", 300, 200, domain.VariantSettings{Width: width(1200), Height: width(1200), Fit: domain.FitInside}, 300, 200}, {"inside keeps the source ratio", 4032, 3024, domain.VariantSettings{Width: width(1000), Height: width(1000), Fit: domain.FitInside}, 1000, 750}, {"height only", 4032, 3024, domain.VariantSettings{Height: width(2400), Fit: domain.FitInside}, 3200, 2400}, {"unknown source size", 0, 0, domain.VariantSettings{Width: width(10), Fit: domain.FitCover}, 0, 0}, } for _, row := range rows { t.Run(row.name, func(t *testing.T) { gotW, gotH := domain.OutputSize(row.sw, row.sh, row.settings) if gotW != row.wantW || gotH != row.wantH { t.Errorf("size = %d x %d, want %d x %d", gotW, gotH, row.wantW, row.wantH) } }) } } func TestOutputFormat(t *testing.T) { all := []domain.VariantFormat{domain.FormatOriginal, domain.FormatJPEG, domain.FormatPNG, domain.FormatWebP} withoutWebP := []domain.VariantFormat{domain.FormatOriginal, domain.FormatJPEG, domain.FormatPNG} rows := []struct { format domain.VariantFormat contentType string encodable []domain.VariantFormat want domain.VariantFormat }{ {domain.FormatOriginal, "image/jpeg", all, domain.FormatJPEG}, {domain.FormatOriginal, "image/png", all, domain.FormatPNG}, {domain.FormatOriginal, "image/webp", all, domain.FormatWebP}, {domain.FormatOriginal, "image/webp", withoutWebP, domain.FormatPNG}, {domain.FormatOriginal, "image/gif", all, domain.FormatPNG}, {domain.FormatWebP, "image/jpeg", withoutWebP, domain.FormatPNG}, {domain.FormatJPEG, "image/png", all, domain.FormatJPEG}, } for _, row := range rows { if got := domain.OutputFormat(row.format, row.contentType, row.encodable); got != row.want { t.Errorf("%s over %s = %s, want %s", row.format, row.contentType, got, row.want) } } } func TestMediaListQueryVariants(t *testing.T) { t.Run("The variants filter and the total_size sort are valid", func(t *testing.T) { query := domain.NewListQuery() query.Variants, query.Sort = domain.VariantsWith, domain.SortTotalSize if err := query.Validate(); err != nil { t.Errorf("err = %v", err) } }) t.Run("Any other variants filter is invalid", func(t *testing.T) { query := domain.NewListQuery() query.Variants = "bogus" if err := query.Validate(); !errors.Is(err, domain.ErrInvalidQuery) { t.Errorf("err = %v", err) } }) } func TestVariantFileRepositoryTotalsBySource(t *testing.T) { repo := persistence.NewVariantFileRepository(openActivityDatabase(t)) save := func(variant string, source string, size int64) { _, _ = repo.Save(domain.VariantFile{VariantName: variant, SourceName: source, CachedName: variant + source, ContentType: "image/jpeg", Size: size, Fingerprint: "f"}) } save("hero", "a.png", 1000) save("thumb", "a.png", 500) save("hero", "b.png", 2000) totals, err := repo.TotalsBySource() if err != nil || len(totals) != 2 || totals["a.png"].Files != 2 || totals["a.png"].Bytes != 1500 || totals["b.png"].Files != 1 || totals["b.png"].Bytes != 2000 { t.Errorf("totals = %+v, err = %v", totals, err) } } func TestPerImageVariantLayering(t *testing.T) { t.Run("The new 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"} files := []string{"ListImageVariants.go", "GenerateImageVariant.go", "GenerateAllImageVariants.go", "PurgeImageVariant.go", "GenerateVariantsOnUpload.go", "ServeVariantGenerate.go", "imageVariantView.go", "ListMedia.go"} for _, name := range files { 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 media handler imports no persistence, mailer, models or gorm package", func(t *testing.T) { for _, file := range []string{"api/handlers/media/mediaHandler.go", "api/handlers/media/variantsHandler.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("Only api/dependecyInjection.go constructs the new use cases", func(t *testing.T) { composition := readRepositoryFile(t, "api/dependecyInjection.go") for _, constructor := range []string{"NewListImageVariantsUseCase(", "NewGenerateImageVariantUseCase(", "NewGenerateAllImageVariantsUseCase(", "NewPurgeImageVariantUseCase(", "NewGenerateVariantsOnUploadUseCase("} { if !strings.Contains(composition, constructor) { t.Errorf("%s is not wired in the composition root", constructor) } if strings.Contains(readRepositoryFile(t, "api/router.go"), constructor) { t.Errorf("api/router.go constructs %s", constructor) } } }) }