85 lines
3.0 KiB
Go
85 lines
3.0 KiB
Go
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(`<svg xmlns="http://www.w3.org/2000/svg"></svg>`), "", ""},
|
||
{"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)
|
||
}
|
||
}
|