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()) } }