all repos — weimar @ 77821058eddf0c6181cacf983976b6f41e5ee037

Unnamed repository; edit this file 'description' to name the repository.

internal/storage/processing_test.go (view raw)

  1package storage
  2
  3import (
  4	"bytes"
  5	"image"
  6	"image/color"
  7	"image/jpeg"
  8	"image/png"
  9	"path/filepath"
 10	"testing"
 11)
 12
 13func TestDetectContentType(t *testing.T) {
 14	tests := []struct {
 15		name string
 16		data []byte
 17		want string
 18	}{
 19		{"JPEG", []byte{0xFF, 0xD8, 0xFF, 0xE0}, "image/jpeg"},
 20		{"PNG", []byte{0x89, 0x50, 0x4E, 0x47}, "image/png"},
 21		{"GIF", []byte{0x47, 0x49, 0x46, 0x38}, "image/gif"},
 22		{"WebP", []byte{0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x45, 0x42, 0x50}, "image/webp"},
 23		{"BMP", []byte{0x42, 0x4D}, "image/bmp"},
 24		{"MP4", []byte{0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70}, "video/mp4"},
 25		{"WebM", []byte{0x1A, 0x45, 0xDF, 0xA3}, "video/webm"},
 26		{"unknown", []byte{0x00, 0x01, 0x02}, "application/octet-stream"},
 27		{"empty", []byte{}, "application/octet-stream"},
 28	}
 29	for _, tt := range tests {
 30		t.Run(tt.name, func(t *testing.T) {
 31			got := DetectContentType(tt.data)
 32			if got != tt.want {
 33				t.Fatalf("DetectContentType = %q, want %q", got, tt.want)
 34			}
 35		})
 36	}
 37}
 38
 39func TestExtensionFromMIME(t *testing.T) {
 40	if ext := ExtensionFromMIME("image/jpeg"); ext != "jpg" {
 41		t.Fatalf("jpg extension mismatch: %s", ext)
 42	}
 43	if ext := ExtensionFromMIME("image/png"); ext != "png" {
 44		t.Fatalf("png extension mismatch: %s", ext)
 45	}
 46	if ext := ExtensionFromMIME("image/gif"); ext != "gif" {
 47		t.Fatalf("gif extension mismatch: %s", ext)
 48	}
 49	if ext := ExtensionFromMIME("video/mp4"); ext != "mp4" {
 50		t.Fatalf("mp4 extension mismatch: %s", ext)
 51	}
 52	if ext := ExtensionFromMIME("application/octet-stream"); ext != "bin" {
 53		t.Fatalf("bin extension mismatch: %s", ext)
 54	}
 55}
 56
 57func TestIsImage(t *testing.T) {
 58	if !IsImage("image/jpeg") {
 59		t.Fatal("expected jpeg to be image")
 60	}
 61	if IsImage("video/mp4") {
 62		t.Fatal("expected mp4 to not be image")
 63	}
 64}
 65
 66func TestIsVideo(t *testing.T) {
 67	if !IsVideo("video/mp4") {
 68		t.Fatal("expected mp4 to be video")
 69	}
 70	if IsVideo("image/jpeg") {
 71		t.Fatal("expected jpeg to not be video")
 72	}
 73}
 74
 75func createTestJPEG(t *testing.T, w, h int) []byte {
 76	t.Helper()
 77	img := image.NewRGBA(image.Rect(0, 0, w, h))
 78	for y := range h {
 79		for x := range w {
 80			img.Set(x, y, color.RGBA{uint8(x % 256), uint8(y % 256), 128, 255})
 81		}
 82	}
 83	var buf bytes.Buffer
 84	if err := jpeg.Encode(&buf, img, nil); err != nil {
 85		t.Fatalf("encode test jpeg: %v", err)
 86	}
 87	return buf.Bytes()
 88}
 89
 90func TestGenerateThumbnail_JPEG(t *testing.T) {
 91	data := createTestJPEG(t, 800, 600)
 92	thumb, err := GenerateThumbnail(data, ThumbnailMaxDimension)
 93	if err != nil {
 94		t.Fatalf("GenerateThumbnail: %v", err)
 95	}
 96	if len(thumb) == 0 {
 97		t.Fatal("expected non-empty thumbnail")
 98	}
 99
100	// Decode and verify dimensions.
101	img, _, err := image.Decode(bytes.NewReader(thumb))
102	if err != nil {
103		t.Fatalf("decode thumbnail: %v", err)
104	}
105	bounds := img.Bounds()
106	if bounds.Dx() > ThumbnailMaxDimension || bounds.Dy() > ThumbnailMaxDimension {
107		t.Fatalf("thumbnail too large: %dx%d", bounds.Dx(), bounds.Dy())
108	}
109}
110
111func TestGenerateThumbnail_SmallImage(t *testing.T) {
112	data := createTestJPEG(t, 50, 50)
113	thumb, err := GenerateThumbnail(data, ThumbnailMaxDimension)
114	if err != nil {
115		t.Fatalf("GenerateThumbnail: %v", err)
116	}
117	if len(thumb) == 0 {
118		t.Fatal("expected non-empty thumbnail for small image")
119	}
120}
121
122func TestGenerateThumbnail_PNG(t *testing.T) {
123	img := image.NewRGBA(image.Rect(0, 0, 400, 300))
124	var buf bytes.Buffer
125	png.Encode(&buf, img)
126	thumb, err := GenerateThumbnail(buf.Bytes(), ThumbnailMaxDimension)
127	if err != nil {
128		t.Fatalf("GenerateThumbnail PNG: %v", err)
129	}
130	if len(thumb) == 0 {
131		t.Fatal("expected non-empty thumbnail")
132	}
133}
134
135func TestGenerateThumbnail_InvalidFormat(t *testing.T) {
136	_, err := GenerateThumbnail([]byte("not an image"), ThumbnailMaxDimension)
137	if err == nil {
138		t.Fatal("expected error for invalid image data")
139	}
140}
141
142func TestThumbnailPath(t *testing.T) {
143	if got := ThumbnailPath("ab/cd/ef/photo.jpg"); got != "ab/cd/ef/photo_thumb.jpg" {
144		t.Fatalf("ThumbnailPath = %q", got)
145	}
146	if got := ThumbnailPath("single.jpg"); got != "single_thumb.jpg" {
147		t.Fatalf("ThumbnailPath = %q", got)
148	}
149}
150
151func TestDetectContentType_RealJPEG(t *testing.T) {
152	data := createTestJPEG(t, 100, 100)
153	mime := DetectContentType(data)
154	if mime != "image/jpeg" {
155		t.Fatalf("mime = %q, want image/jpeg", mime)
156	}
157}
158
159func TestStripEXIF_NoEXIF(t *testing.T) {
160	data := createTestJPEG(t, 100, 100)
161	cleaned, err := StripEXIF(data)
162	if err != nil {
163		t.Fatalf("StripEXIF: %v", err)
164	}
165	if len(cleaned) == 0 {
166		t.Fatal("expected non-empty cleaned data")
167	}
168}
169
170func TestDecodeImage(t *testing.T) {
171	data := createTestJPEG(t, 640, 480)
172	cfg, _, err := DecodeImage(data)
173	if err != nil {
174		t.Fatalf("DecodeImage: %v", err)
175	}
176	if cfg.Bounds().Dx() != 640 {
177		t.Fatalf("width = %d, want 640", cfg.Bounds().Dx())
178	}
179	if cfg.Bounds().Dy() != 480 {
180		t.Fatalf("height = %d, want 480", cfg.Bounds().Dy())
181	}
182}
183
184func TestDecodeImage_Invalid(t *testing.T) {
185	_, _, err := DecodeImage([]byte("not an image"))
186	if err == nil {
187		t.Fatal("expected error for invalid image")
188	}
189}
190
191func TestFFmpegAvailable(t *testing.T) {
192	FFmpegAvailable()
193}
194
195func TestGenerateVideoThumbnail_Skipped(t *testing.T) {
196	dir := t.TempDir()
197	input := filepath.Join(dir, "test.mp4")
198	output := filepath.Join(dir, "out.jpg")
199
200	err := GenerateVideoThumbnail(input, output)
201	if err == nil {
202		t.Fatal("expected error for non-existent video")
203	}
204}