Files
RenewCMS/test/image_upload_rules_test.go
2026-10-06 22:25:23 +02:00

120 lines
4.1 KiB
Go

package test
import (
imageDomain "RenewCMS/internal/domain/image"
"RenewCMS/internal/infrastructure/useCases"
"bytes"
"errors"
"testing"
)
func validBytesFor(t *testing.T, contentType string) []byte {
t.Helper()
switch contentType {
case "image/png":
return pngBytes(t, 3, 2)
case "image/jpeg":
return jpegBytes(t, 3, 2)
case "image/webp":
return webpBytes(t)
default:
return []byte(svgFixture)
}
}
func paddedTo(data []byte, size int) []byte {
padding := byte(0)
if bytes.HasPrefix(data, []byte("<svg")) {
padding = ' '
}
return append(append([]byte{}, data...), bytes.Repeat([]byte{padding}, size-len(data))...)
}
func inputOf(content []byte, contentType string) imageDomain.ImageInput {
return imageDomain.ImageInput{Content: bytes.NewReader(content), Filename: "upload", ContentType: contentType}
}
func TestImageUploadRules(t *testing.T) {
t.Run("CreateImage accepts every allowed content type within the size limit", func(t *testing.T) {
for _, contentType := range []string{"image/png", "image/jpeg", "image/webp", "image/svg+xml"} {
t.Run(contentType, func(t *testing.T) {
repo := newMockImageRepo()
createUc := useCases.NewCreateImageUseCase(repo, newMockImageStorage(), discardRecorder)
result, err := createUc.CreateImage(testCtx, inputOf(paddedTo(validBytesFor(t, contentType), int(imageDomain.MaxImageSize)), contentType))
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if result.ID == 0 {
t.Errorf("expected the created image, got zero value")
}
if len(repo.images) != 1 {
t.Errorf("expected Create to be called once, got %d calls", len(repo.images))
}
})
}
})
t.Run("CreateImage rejects a disallowed content type before reaching the repository", func(t *testing.T) {
repo := newMockImageRepo()
createUc := useCases.NewCreateImageUseCase(repo, newMockImageStorage(), discardRecorder)
_, err := createUc.CreateImage(testCtx, inputOf([]byte("%PDF"), "application/pdf"))
if !errors.Is(err, imageDomain.ErrImageTypeNotAllowed) {
t.Fatalf("expected ErrImageTypeNotAllowed, got %v", err)
}
if len(repo.images) != 0 {
t.Errorf("expected Create to never be called, got %d calls", len(repo.images))
}
})
t.Run("CreateImage rejects a file that exceeds the size limit", func(t *testing.T) {
repo := newMockImageRepo()
createUc := useCases.NewCreateImageUseCase(repo, newMockImageStorage(), discardRecorder)
_, err := createUc.CreateImage(testCtx, inputOf(paddedTo(pngBytes(t, 3, 2), int(imageDomain.MaxImageSize)+1), "image/png"))
if !errors.Is(err, imageDomain.ErrImageTooLarge) {
t.Fatalf("expected ErrImageTooLarge, got %v", err)
}
if len(repo.images) != 0 {
t.Errorf("expected Create to never be called, got %d calls", len(repo.images))
}
})
t.Run("A file exactly at the size limit is accepted, one byte over is not", func(t *testing.T) {
repo := newMockImageRepo()
createUc := useCases.NewCreateImageUseCase(repo, newMockImageStorage(), discardRecorder)
_, err := createUc.CreateImage(testCtx, inputOf(paddedTo(pngBytes(t, 3, 2), int(imageDomain.MaxImageSize)), "image/png"))
if err != nil {
t.Fatalf("expected no error at the exact limit, got %v", err)
}
if len(repo.images) != 1 {
t.Fatalf("expected Create to be called once, got %d calls", len(repo.images))
}
_, err = createUc.CreateImage(testCtx, inputOf(paddedTo(pngBytes(t, 3, 2), int(imageDomain.MaxImageSize)+1), "image/png"))
if !errors.Is(err, imageDomain.ErrImageTooLarge) {
t.Fatalf("expected ErrImageTooLarge, got %v", err)
}
if len(repo.images) != 1 {
t.Errorf("expected Create to still be called exactly once in total, got %d calls", len(repo.images))
}
})
t.Run("A repository failure unrelated to type or size still propagates unchanged", func(t *testing.T) {
repo := newMockImageRepo()
repo.fail.failNextWith("Create", errRepositoryFailure)
createUc := useCases.NewCreateImageUseCase(repo, newMockImageStorage(), discardRecorder)
_, err := createUc.CreateImage(testCtx, inputOf(pngBytes(t, 3, 2), "image/png"))
if !errors.Is(err, errRepositoryFailure) {
t.Fatalf("expected the generic repository error, got %v", err)
}
})
}