check / check (push) Waiting to run
magic.DetectFormat returns an imagerequest.Format. ValidateMagicBytes returns the format it checked against the upstream Content-Type. The cache reads a cached source's format from its file's first bytes, as it reads a variant's. The proxy hands the format to Process. Process refuses a format that is not a source format, and input libvips would load with another loader, such as an SVG passing as AVIF. Format.MIMEType declares each MIME string once, and the fetcher, the cache's variant read and the Accept matching use it. magic.MIMEType, magic.ImageFormat, MIMEToImageFormat, magic's SVG detection, detectFormat, formatFromString, FormatToMIME and Result.InputFormat are gone. Model: opus-5-5
204 lines
5.2 KiB
Go
204 lines
5.2 KiB
Go
package magic
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
// Shared test fixture strings.
|
|
const (
|
|
testNameEmpty = "empty"
|
|
testMIMEJPEG = "image/jpeg"
|
|
testMIMEJPEGParams = "image/jpeg; charset=utf-8"
|
|
testMIMEPNG = "image/png"
|
|
)
|
|
|
|
// pad appends zero bytes so data is comfortably above MinMagicBytes.
|
|
func pad(b ...byte) []byte {
|
|
return append(b, make([]byte, 100)...)
|
|
}
|
|
|
|
func TestDetectFormat(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
jpeg := pad(0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01)
|
|
png := pad(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D)
|
|
gif87a := pad(0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0, 0, 0, 0, 0, 0)
|
|
gif89a := pad(0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0, 0, 0, 0, 0, 0)
|
|
// RIFF + size placeholder + WEBP
|
|
webp := pad(0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x45, 0x42, 0x50)
|
|
// box size + ftyp + brand
|
|
avif := pad(0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66)
|
|
avis := pad(0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x73)
|
|
|
|
tests := []struct {
|
|
name string
|
|
data []byte
|
|
wantFormat imagerequest.Format
|
|
wantErr error
|
|
}{
|
|
{name: "JPEG", data: jpeg, wantFormat: imagerequest.FormatJPEG},
|
|
{name: "PNG", data: png, wantFormat: imagerequest.FormatPNG},
|
|
{name: "GIF87a", data: gif87a, wantFormat: imagerequest.FormatGIF},
|
|
{name: "GIF89a", data: gif89a, wantFormat: imagerequest.FormatGIF},
|
|
{name: "WebP", data: webp, wantFormat: imagerequest.FormatWebP},
|
|
{name: "AVIF", data: avif, wantFormat: imagerequest.FormatAVIF},
|
|
{name: "AVIF sequence", data: avis, wantFormat: imagerequest.FormatAVIF},
|
|
{
|
|
name: "SVG",
|
|
data: []byte(`<svg xmlns="http://www.w3.org/2000/svg"></svg>`),
|
|
wantErr: ErrUnknownFormat,
|
|
},
|
|
{
|
|
name: "unknown format",
|
|
data: make([]byte, MinMagicBytes),
|
|
wantErr: ErrUnknownFormat,
|
|
},
|
|
{name: "too short", data: []byte{0xFF, 0xD8}, wantErr: ErrNotEnoughData},
|
|
{name: testNameEmpty, data: []byte{}, wantErr: ErrNotEnoughData},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got, err := DetectFormat(tt.data)
|
|
if !errors.Is(err, tt.wantErr) {
|
|
t.Errorf("DetectFormat() error = %v, wantErr %v", err, tt.wantErr)
|
|
|
|
return
|
|
}
|
|
|
|
if got != tt.wantFormat {
|
|
t.Errorf("DetectFormat() = %v, want %v", got, tt.wantFormat)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateMagicBytes(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
jpegData := pad(0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01)
|
|
pngData := pad(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D)
|
|
|
|
tests := []struct {
|
|
name string
|
|
data []byte
|
|
declaredType string
|
|
wantFormat imagerequest.Format
|
|
wantErr error
|
|
}{
|
|
{
|
|
name: "matching JPEG",
|
|
data: jpegData,
|
|
declaredType: testMIMEJPEG,
|
|
wantFormat: imagerequest.FormatJPEG,
|
|
wantErr: nil,
|
|
},
|
|
{
|
|
name: "matching JPEG with params",
|
|
data: jpegData,
|
|
declaredType: testMIMEJPEGParams,
|
|
wantFormat: imagerequest.FormatJPEG,
|
|
wantErr: nil,
|
|
},
|
|
{
|
|
name: "matching PNG",
|
|
data: pngData,
|
|
declaredType: testMIMEPNG,
|
|
wantFormat: imagerequest.FormatPNG,
|
|
wantErr: nil,
|
|
},
|
|
{
|
|
name: "mismatched type",
|
|
data: jpegData,
|
|
declaredType: testMIMEPNG,
|
|
wantErr: ErrMagicByteMismatch,
|
|
},
|
|
{
|
|
name: "unknown data",
|
|
data: make([]byte, MinMagicBytes),
|
|
declaredType: testMIMEJPEG,
|
|
wantErr: ErrUnknownFormat,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got, err := ValidateMagicBytes(tt.data, tt.declaredType)
|
|
|
|
if !errors.Is(err, tt.wantErr) {
|
|
t.Errorf("ValidateMagicBytes() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
|
|
if got != tt.wantFormat {
|
|
t.Errorf("ValidateMagicBytes() = %q, want %q", got, tt.wantFormat)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeMIMEType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{testMIMEJPEG, testMIMEJPEG},
|
|
{"IMAGE/JPEG", testMIMEJPEG},
|
|
{testMIMEJPEGParams, testMIMEJPEG},
|
|
{" image/jpeg ", testMIMEJPEG},
|
|
{"image/jpeg; boundary=something", testMIMEJPEG},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got := normalizeMIMEType(tt.input)
|
|
|
|
if got != tt.want {
|
|
t.Errorf("normalizeMIMEType(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDetectFormatRIFFNotWebP(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// RIFF container but not WebP (e.g., WAV file)
|
|
wavData := []byte{
|
|
0x52, 0x49, 0x46, 0x46, // RIFF
|
|
0x00, 0x00, 0x00, 0x00, // file size
|
|
0x57, 0x41, 0x56, 0x45, // WAVE (not WEBP)
|
|
}
|
|
|
|
_, err := DetectFormat(wavData)
|
|
if !errors.Is(err, ErrUnknownFormat) {
|
|
t.Errorf("DetectFormat(WAV) error = %v, want %v", err, ErrUnknownFormat)
|
|
}
|
|
}
|
|
|
|
func TestDetectFormatFtypNotAVIF(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// ftyp container but not AVIF (e.g., MP4)
|
|
mp4Data := []byte{
|
|
0x00, 0x00, 0x00, 0x1C, // box size
|
|
0x66, 0x74, 0x79, 0x70, // ftyp
|
|
0x69, 0x73, 0x6F, 0x6D, // isom brand (not avif)
|
|
}
|
|
|
|
_, err := DetectFormat(mp4Data)
|
|
if !errors.Is(err, ErrUnknownFormat) {
|
|
t.Errorf("DetectFormat(MP4) error = %v, want %v", err, ErrUnknownFormat)
|
|
}
|
|
}
|