|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "image" |
| 6 | + "image/color" |
| 7 | + "image/jpeg" |
| 8 | + _ "image/png" |
| 9 | + "os" |
| 10 | + "path/filepath" |
| 11 | + "testing" |
| 12 | + |
| 13 | + "github.com/nfnt/resize" |
| 14 | +) |
| 15 | + |
| 16 | +// TestJpegThumbnail covers the in-memory thumbnail encoding that replaced the |
| 17 | +// leaking temp-file path in SendImage: it must return decodable JPEG bytes |
| 18 | +// bounded by the requested size, preserving aspect ratio. |
| 19 | +func TestJpegThumbnail(t *testing.T) { |
| 20 | + // A 200x100 source image (2:1 aspect). |
| 21 | + src := image.NewRGBA(image.Rect(0, 0, 200, 100)) |
| 22 | + for x := 0; x < 200; x++ { |
| 23 | + for y := 0; y < 100; y++ { |
| 24 | + src.Set(x, y, color.RGBA{R: uint8(x), G: uint8(y), B: 0, A: 255}) |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + out, err := jpegThumbnail(src, 72, 72) |
| 29 | + if err != nil { |
| 30 | + t.Fatalf("jpegThumbnail: %v", err) |
| 31 | + } |
| 32 | + if len(out) == 0 { |
| 33 | + t.Fatal("jpegThumbnail returned no bytes") |
| 34 | + } |
| 35 | + |
| 36 | + cfg, format, err := image.DecodeConfig(bytes.NewReader(out)) |
| 37 | + if err != nil { |
| 38 | + t.Fatalf("output is not a decodable image: %v", err) |
| 39 | + } |
| 40 | + if format != "jpeg" { |
| 41 | + t.Errorf("format = %q; want jpeg", format) |
| 42 | + } |
| 43 | + if cfg.Width == 0 || cfg.Height == 0 { |
| 44 | + t.Errorf("thumbnail has a zero dimension: %dx%d", cfg.Width, cfg.Height) |
| 45 | + } |
| 46 | + if cfg.Width > 72 || cfg.Height > 72 { |
| 47 | + t.Errorf("thumbnail %dx%d exceeds the 72x72 bound", cfg.Width, cfg.Height) |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +// TestJpegThumbnailNil verifies the nil-image guard returns an error instead of |
| 52 | +// panicking (resize.Thumbnail dereferences the image's bounds). |
| 53 | +func TestJpegThumbnailNil(t *testing.T) { |
| 54 | + if _, err := jpegThumbnail(nil, 72, 72); err == nil { |
| 55 | + t.Error("expected an error for a nil image, got nil") |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +// TestJpegThumbnailRealImage runs the fix end-to-end against a real image file |
| 60 | +// shipped with the project. It decodes the image exactly like SendImage does |
| 61 | +// (image.Decode), produces the thumbnail, and asserts the output is byte-for-byte |
| 62 | +// identical to the previous resize+encode — so removing the temp file changed |
| 63 | +// nothing but the mechanism — and is a valid, bounded JPEG. |
| 64 | +func TestJpegThumbnailRealImage(t *testing.T) { |
| 65 | + data, err := os.ReadFile(filepath.Join("static", "images", "background_image.png")) |
| 66 | + if err != nil { |
| 67 | + t.Skipf("real image not available: %v", err) |
| 68 | + } |
| 69 | + |
| 70 | + img, format, err := image.Decode(bytes.NewReader(data)) |
| 71 | + if err != nil { |
| 72 | + t.Fatalf("decode real image: %v", err) |
| 73 | + } |
| 74 | + t.Logf("decoded a real %s image: %dx%d (%T)", format, img.Bounds().Dx(), img.Bounds().Dy(), img) |
| 75 | + |
| 76 | + got, err := jpegThumbnail(img, 72, 72) |
| 77 | + if err != nil { |
| 78 | + t.Fatalf("jpegThumbnail on real image: %v", err) |
| 79 | + } |
| 80 | + |
| 81 | + // Reference: the exact resize + JPEG encode the old temp-file path performed. |
| 82 | + var ref bytes.Buffer |
| 83 | + if err := jpeg.Encode(&ref, resize.Thumbnail(72, 72, img, resize.Lanczos3), nil); err != nil { |
| 84 | + t.Fatalf("reference encode: %v", err) |
| 85 | + } |
| 86 | + if !bytes.Equal(got, ref.Bytes()) { |
| 87 | + t.Errorf("thumbnail differs from the resize+encode reference (%d vs %d bytes)", len(got), ref.Len()) |
| 88 | + } |
| 89 | + |
| 90 | + cfg, f, err := image.DecodeConfig(bytes.NewReader(got)) |
| 91 | + if err != nil { |
| 92 | + t.Fatalf("thumbnail is not a decodable image: %v", err) |
| 93 | + } |
| 94 | + t.Logf("thumbnail produced: %s %dx%d, %d bytes", f, cfg.Width, cfg.Height, len(got)) |
| 95 | + if f != "jpeg" || cfg.Width == 0 || cfg.Width > 72 || cfg.Height > 72 { |
| 96 | + t.Errorf("unexpected thumbnail: format=%s size=%dx%d", f, cfg.Width, cfg.Height) |
| 97 | + } |
| 98 | +} |
0 commit comments