package handlers import ( "strings" "testing" ) // TestSniffImage — белый список форматов по сигнатуре: только фото. func TestSniffImage(t *testing.T) { jpeg := []byte{0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10} png := []byte{0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A, 0x00} webp := []byte("RIFF\x24\x00\x00\x00WEBPVP8 ") cases := []struct { name string data []byte contentType string ext string }{ {"jpeg", jpeg, "image/jpeg", "jpg"}, {"png", png, "image/png", "png"}, {"webp", webp, "image/webp", "webp"}, {"gif is not photo", []byte("GIF89a"), "", ""}, {"bmp is not photo", []byte("BM\x00\x00"), "", ""}, {"svg text", []byte(``), "", ""}, {"empty", nil, "", ""}, {"truncated jpeg", []byte{0xFF, 0xD8}, "", ""}, {"riff but not webp", []byte("RIFF\x00\x00\x00\x00WAVEfmt "), "", ""}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { contentType, ext, ok := sniffImage(tc.data) if tc.contentType == "" { if ok { t.Errorf("sniff = (%q, %q, true), want reject", contentType, ext) } return } if !ok || contentType != tc.contentType || ext != tc.ext { t.Errorf("sniff = (%q, %q, %v), want (%q, %q, true)", contentType, ext, ok, tc.contentType, tc.ext) } }) } } // TestPhotoName — имя файла из multipart: без путей, управляющих // символов и без бесконечных строк (оно уходит в журнал событий). func TestPhotoName(t *testing.T) { cases := []struct { in string want string }{ {"photo.jpg", "photo.jpg"}, {`C:\Users\me\photo.jpg`, "photo.jpg"}, // имя с Windows-путём {"../../etc/passwd", "passwd"}, // path traversal вырезается {"a\x00b\x1fc.png", "abc.png"}, // управляющие символы {"", ""}, // имя не передали {".", ""}, // path.Base(".") = "." {strings.Repeat("я", 150) + ".jpg", strings.Repeat("я", 100)}, // обрезка по рунам } for _, tc := range cases { if got := photoName(tc.in); got != tc.want { t.Errorf("photoName(%q) = %q, want %q", tc.in, got, tc.want) } } } // TestNewPhotoHandlerDefaults — лимиты из env могли быть нулём // (не заданы): хендлер обязан подставить дефолты, а не считать с нулём. func TestNewPhotoHandlerDefaults(t *testing.T) { h := NewPhotoHandler(nil, nil, nil, nil, 0, -1) if h.maxBytes != photoDefaultMaxBytes { t.Errorf("maxBytes = %d, want %d", h.maxBytes, photoDefaultMaxBytes) } if h.maxPer != photoDefaultMaxPer { t.Errorf("maxPer = %d, want %d", h.maxPer, photoDefaultMaxPer) } custom := NewPhotoHandler(nil, nil, nil, nil, 4096, 3) if custom.maxBytes != 4096 || custom.maxPer != 3 { t.Errorf("custom limits = %d/%d, want 4096/3", custom.maxBytes, custom.maxPer) } }