check / check (push) Canceled after 0s
The new package internal/imagerequest holds the request type, its two parts Source and Transform, the Format and Fit types, the dimension and fit checks, the /v1/image/ path parsing and the variant key; it imports no other package of pixa. imgcache.ParsedURL, imgcache.ImageRequest, signature.Request, imageprocessor.Request, the second Size, format and fit types and the conversions between them are gone. The image processor takes a Transform only. encurl keeps a private struct with the token's short CBOR field names. VariantKey moves with the function that makes it. Tests follow the moved and renamed code; the tests of the removed conversions go with them. Model: opus-5-5
95 lines
3.2 KiB
Go
95 lines
3.2 KiB
Go
package imageprocessor
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"os"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
// TestImageProcessor_RefusesAVIFAboveMaxPixels verifies that an AVIF output
|
|
// of more than MaxAVIFOutputPixels is refused with ErrAVIFOutputTooLarge
|
|
// before anything is decoded, whatever size and fit give it, the source's own
|
|
// size included, and that an AVIF output of at most that many pixels, or one
|
|
// in another format, is not. One input is a 64x32 PNG cut off in its pixel
|
|
// data. The other is testdata/red.avif, a 4x4 AVIF, with the size in its
|
|
// header changed to 4097x4096. libvips reads each input's size from its
|
|
// header but fails when it decodes its pixel data, so a request that gets
|
|
// that failure was not refused, and a refusal came before any decoding.
|
|
func TestImageProcessor_RefusesAVIFAboveMaxPixels(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
whole := createTestPNG(t, 64, 32)
|
|
cutOff := whole[:len(whole)/2]
|
|
|
|
largeAVIF, err := os.ReadFile("testdata/red.avif")
|
|
if err != nil {
|
|
t.Fatalf("failed to read test AVIF: %v", err)
|
|
}
|
|
|
|
// The ispe box gives the width and then the height, 4 bytes each, after
|
|
// the box's type and its 4 bytes of version and flags
|
|
ispe := bytes.Index(largeAVIF, []byte("ispe"))
|
|
binary.BigEndian.PutUint32(largeAVIF[ispe+8:], 4097)
|
|
binary.BigEndian.PutUint32(largeAVIF[ispe+12:], 4096)
|
|
|
|
tests := []struct {
|
|
name string
|
|
input []byte
|
|
format imagerequest.Format
|
|
width, height int
|
|
fit imagerequest.Fit
|
|
refused bool
|
|
}{
|
|
{"AVIF at the limit", cutOff, imagerequest.FormatAVIF,
|
|
4096, 4096, imagerequest.FitCover, false},
|
|
{"AVIF above the limit", cutOff, imagerequest.FormatAVIF,
|
|
4096, 4097, imagerequest.FitCover, true},
|
|
{"WebP above the AVIF limit", cutOff, imagerequest.FormatWebP,
|
|
4096, 4097, imagerequest.FitCover, false},
|
|
// FitInside does not enlarge, so the output stays 64x32
|
|
{"AVIF inside a larger size", cutOff, imagerequest.FormatAVIF,
|
|
8192, 8192, imagerequest.FitInside, false},
|
|
// FitOutside scales 64x32 by 128 to cover 8192x1: 8192x4096
|
|
{"AVIF outside a smaller size", cutOff, imagerequest.FormatAVIF,
|
|
8192, 1, imagerequest.FitOutside, true},
|
|
// With no size, the output keeps the source's 4097x4096
|
|
{"AVIF of the source's size", largeAVIF, imagerequest.FormatAVIF,
|
|
0, 0, imagerequest.FitCover, true},
|
|
{"orig of an AVIF source", largeAVIF, imagerequest.FormatOriginal,
|
|
0, 0, imagerequest.FitCover, true},
|
|
{"JPEG of the source's size", largeAVIF, imagerequest.FormatJPEG,
|
|
0, 0, imagerequest.FitCover, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := New(Params{}).Process(t.Context(), bytes.NewReader(tt.input),
|
|
&imagerequest.Transform{
|
|
Size: imagerequest.Size{Width: tt.width, Height: tt.height},
|
|
Format: tt.format,
|
|
FitMode: tt.fit,
|
|
})
|
|
t.Logf("Process() error = %v", err)
|
|
|
|
if tt.refused {
|
|
if !errors.Is(err, ErrAVIFOutputTooLarge) {
|
|
t.Errorf("Process() error = %v, want %v", err, ErrAVIFOutputTooLarge)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if err == nil || errors.Is(err, ErrAVIFOutputTooLarge) {
|
|
t.Errorf("Process() error = %v, want the failure to decode "+
|
|
"the input", err)
|
|
}
|
|
})
|
|
}
|
|
}
|