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

130 lines
4.3 KiB
Go

package test
import (
domain "RenewCMS/internal/domain/image"
"bytes"
"errors"
"image"
"image/color"
"image/gif"
"testing"
)
func bandedTallImage() *image.NRGBA {
canvas := image.NewNRGBA(image.Rect(0, 0, 20, 60))
for y := 0; y < 60; y++ {
fill := variantGreen
if y < 15 {
fill = variantRed
}
if y >= 45 {
fill = variantBlue
}
for x := 0; x < 20; x++ {
canvas.SetNRGBA(x, y, fill)
}
}
return canvas
}
func globalPaletteGIF(t *testing.T, frames int) []byte {
t.Helper()
palette := color.Palette{color.White, color.Black, color.RGBA{R: 255, A: 255}, color.RGBA{B: 255, A: 255}}
animation := &gif.GIF{Config: image.Config{ColorModel: palette, Width: 8, Height: 8}}
for frame := 0; frame < frames; frame++ {
paletted := image.NewPaletted(image.Rect(0, 0, 8, 8), palette)
paletted.SetColorIndex(frame, frame, 1)
animation.Image = append(animation.Image, paletted)
animation.Delay = append(animation.Delay, 10)
}
var buffer bytes.Buffer
if err := gif.EncodeAll(&buffer, animation); err != nil {
t.Fatalf("gif encode failed: %v", err)
}
return buffer.Bytes()
}
func TestVariantGeometryPixelGaps(t *testing.T) {
t.Run("Cover on a tall source keeps the middle band", func(t *testing.T) {
rendered := renderVariant(t, encodePNG(t, bandedTallImage()), variantSettings(20, 20, domain.FitCover, domain.FormatPNG))
decoded, _ := decodeImage(t, rendered.Content)
if decoded.Bounds().Dx() != 20 || decoded.Bounds().Dy() != 20 {
t.Fatalf("output = %v", decoded.Bounds())
}
for _, y := range []int{0, 10, 19} {
if got := pixelAt(decoded, 10, y); got != variantGreen {
t.Errorf("pixel 10,%d = %v, want green", y, got)
}
}
})
t.Run("Inside on a tall source scales the whole picture", func(t *testing.T) {
rendered := renderVariant(t, encodePNG(t, bandedTallImage()), variantSettings(10, 30, domain.FitInside, domain.FormatPNG))
decoded, _ := decodeImage(t, rendered.Content)
if decoded.Bounds().Dx() != 10 || decoded.Bounds().Dy() != 30 {
t.Fatalf("output = %v", decoded.Bounds())
}
want := map[int]color.NRGBA{1: variantRed, 15: variantGreen, 28: variantBlue}
for y, expected := range want {
assertNearColor(t, pixelAt(decoded, 5, y), expected)
}
})
t.Run("Contain pads horizontally around a narrow source", func(t *testing.T) {
rendered := renderVariant(t, encodePNG(t, variantSolidImage(20, 40, variantRed)), variantSettings(40, 40, domain.FitContain, domain.FormatPNG))
decoded, _ := decodeImage(t, rendered.Content)
for y := 0; y < 40; y += 13 {
for _, x := range []int{0, 9, 30, 39} {
if got := pixelAt(decoded, x, y); got.A != 0 {
t.Fatalf("pixel %d,%d = %v, want transparent", x, y, got)
}
}
for _, x := range []int{10, 19, 29} {
if got := pixelAt(decoded, x, y); got != variantRed {
t.Fatalf("pixel %d,%d = %v, want red", x, y, got)
}
}
}
})
t.Run("Contain keeps a box that is larger in one direction only", func(t *testing.T) {
for _, row := range []struct{ width, height, wantWidth, wantHeight int }{
{200, 100, 200, 100},
{100, 200, 100, 200},
} {
rendered := renderVariant(t, solidPNG(t, 100, 100), variantSettings(row.width, row.height, domain.FitContain, domain.FormatPNG))
width, height := decodedSize(t, rendered.Content)
if width != row.wantWidth || height != row.wantHeight {
t.Errorf("output = %dx%d, want %dx%d", width, height, row.wantWidth, row.wantHeight)
}
}
})
}
func TestAnimatedGIFDetectionWithGlobalPalette(t *testing.T) {
animated, err := domain.IsAnimatedGIF(bytes.NewReader(globalPaletteGIF(t, 2)))
if err != nil || !animated {
t.Errorf("two frames: animated = %v, err = %v", animated, err)
}
animated, err = domain.IsAnimatedGIF(bytes.NewReader(globalPaletteGIF(t, 1)))
if err != nil || animated {
t.Errorf("one frame: animated = %v, err = %v", animated, err)
}
}
func TestVariantRequestErrorMessages(t *testing.T) {
unknown := domain.NewUnknownVariantError("thumb")
if unknown.Error() != "unknown variant: thumb" || !errors.Is(unknown, domain.ErrUnknownVariant) {
t.Errorf("unknown = %q", unknown.Error())
}
unsupported := domain.NewUnsupportedParameterError("w")
if unsupported.Error() != "unsupported parameter: w" || !errors.Is(unsupported, domain.ErrUnsupportedParameter) {
t.Errorf("unsupported = %q", unsupported.Error())
}
}