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(``), 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) } }