1package provider
2
3import (
4 "bytes"
5 "image"
6 "image/color"
7 "image/jpeg"
8 "image/png"
9 "testing"
10)
11
12func makeRect(w, h int) image.Image {
13 img := image.NewRGBA(image.Rect(0, 0, w, h))
14 // Fill with a recognisable colour so a buggy resize that goes
15 // transparent or zero-size is obvious.
16 c := color.RGBA{R: 80, G: 200, B: 120, A: 255}
17 for y := 0; y < h; y++ {
18 for x := 0; x < w; x++ {
19 img.Set(x, y, c)
20 }
21 }
22 return img
23}
24
25func encodePNG(t *testing.T, img image.Image) []byte {
26 t.Helper()
27 var buf bytes.Buffer
28 if err := png.Encode(&buf, img); err != nil {
29 t.Fatalf("encode png: %v", err)
30 }
31 return buf.Bytes()
32}
33
34func encodeJPEG(t *testing.T, img image.Image) []byte {
35 t.Helper()
36 var buf bytes.Buffer
37 if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 90}); err != nil {
38 t.Fatalf("encode jpeg: %v", err)
39 }
40 return buf.Bytes()
41}
42
43func decodeConfig(t *testing.T, data []byte) image.Config {
44 t.Helper()
45 cfg, _, err := image.DecodeConfig(bytes.NewReader(data))
46 if err != nil {
47 t.Fatalf("decode config: %v", err)
48 }
49 return cfg
50}
51
52func TestAnthShrinkImage_PassesThroughWhenSmall(t *testing.T) {
53 src := encodePNG(t, makeRect(800, 600))
54 out, mime := anthShrinkImageBytesIfTooBig(src, "image/png")
55 if !bytes.Equal(out, src) {
56 t.Errorf("small image was rewritten; expected pass-through")
57 }
58 if mime != "image/png" {
59 t.Errorf("mime changed unexpectedly: %s", mime)
60 }
61}
62
63func TestAnthShrinkImage_DownscalesWhenTooWide(t *testing.T) {
64 src := encodePNG(t, makeRect(4000, 1000))
65 out, mime := anthShrinkImageBytesIfTooBig(src, "image/png")
66 if bytes.Equal(out, src) {
67 t.Fatalf("image was not resized")
68 }
69 if mime != "image/png" {
70 t.Errorf("mime changed: %s", mime)
71 }
72 cfg := decodeConfig(t, out)
73 if cfg.Width != anthMaxImageSide {
74 t.Errorf("width: got %d want %d", cfg.Width, anthMaxImageSide)
75 }
76 // Aspect ratio preserved: 4000:1000 -> 2000:500.
77 if cfg.Height != 500 {
78 t.Errorf("height: got %d want 500", cfg.Height)
79 }
80}
81
82func TestAnthShrinkImage_DownscalesWhenTooTall(t *testing.T) {
83 src := encodePNG(t, makeRect(1500, 6000))
84 out, _ := anthShrinkImageBytesIfTooBig(src, "image/png")
85 cfg := decodeConfig(t, out)
86 if cfg.Height != anthMaxImageSide {
87 t.Errorf("height: got %d want %d", cfg.Height, anthMaxImageSide)
88 }
89 // 1500:6000 -> 500:2000.
90 if cfg.Width != 500 {
91 t.Errorf("width: got %d want 500", cfg.Width)
92 }
93}
94
95func TestAnthShrinkImage_PreservesJPEGFormat(t *testing.T) {
96 src := encodeJPEG(t, makeRect(3000, 2500))
97 out, mime := anthShrinkImageBytesIfTooBig(src, "image/jpeg")
98 if mime != "image/jpeg" {
99 t.Errorf("mime should stay image/jpeg, got %s", mime)
100 }
101 cfg := decodeConfig(t, out)
102 if cfg.Width > anthMaxImageSide || cfg.Height > anthMaxImageSide {
103 t.Errorf("dimensions exceed cap: %dx%d", cfg.Width, cfg.Height)
104 }
105}
106
107func TestAnthShrinkImage_BadDataReturnsOriginal(t *testing.T) {
108 src := []byte("not an image at all")
109 out, mime := anthShrinkImageBytesIfTooBig(src, "image/png")
110 if !bytes.Equal(out, src) {
111 t.Errorf("garbage input was mutated")
112 }
113 if mime != "image/png" {
114 t.Errorf("mime was changed on bad input: %s", mime)
115 }
116}