check / check (push) Canceled after 0s
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
142 lines
4.5 KiB
Go
142 lines
4.5 KiB
Go
package imageprocessor
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
// TestImageProcessor_RefusesComputedSideAboveMaximum verifies that a size
|
|
// with one side 0, which Process computes from the input's proportions, is
|
|
// served when that side comes out at MaxOutputDimension and refused with
|
|
// ErrOutputTooLarge when it would be above. A 4096x1 or 1x4096 input given
|
|
// 2 for its short side has 8192 for its long side.
|
|
func TestImageProcessor_RefusesComputedSideAboveMaximum(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputWidth, inputHeight int
|
|
size imagerequest.Size
|
|
wantErr error
|
|
}{
|
|
{"width at the maximum", 4096, 1,
|
|
imagerequest.Size{Height: 2}, nil},
|
|
{"width above the maximum", 4096, 1,
|
|
imagerequest.Size{Height: 3}, ErrOutputTooLarge},
|
|
{"height at the maximum", 1, 4096,
|
|
imagerequest.Size{Width: 2}, nil},
|
|
{"height above the maximum", 1, 4096,
|
|
imagerequest.Size{Width: 3}, ErrOutputTooLarge},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
input := createTestJPEG(t, tt.inputWidth, tt.inputHeight)
|
|
|
|
result, err := New(Params{
|
|
MaxInputBytes: 50 << 20,
|
|
MaxConcurrentProcessing: 1,
|
|
}).Process(t.Context(),
|
|
bytes.NewReader(input), imagerequest.FormatJPEG,
|
|
&imagerequest.Transform{
|
|
Size: tt.size,
|
|
Format: imagerequest.FormatJPEG,
|
|
FitMode: imagerequest.FitCover,
|
|
})
|
|
if result != nil {
|
|
t.Logf("Process() made %dx%d", result.Width, result.Height)
|
|
|
|
if max(result.Width, result.Height) != MaxOutputDimension {
|
|
t.Errorf("Process() made %dx%d, want a side of %d",
|
|
result.Width, result.Height, MaxOutputDimension)
|
|
}
|
|
}
|
|
|
|
if !errors.Is(err, tt.wantErr) {
|
|
t.Errorf("Process() error = %v, want %v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestImageProcessor_ComputedSideIsAtLeastOne verifies that, for a size with
|
|
// one side 0, the side computed from the input's proportions is 1 where it
|
|
// would round down to 0, and that Process makes that size in every fit mode
|
|
// but FitOutside, which scales the input to cover the size and so can make
|
|
// it longer. Each case checks the size targetDimensions gives before it
|
|
// calls Process: with that side at 0, an 8192x1 input at 1300x0 makes
|
|
// libvips ask for about 39 GB with FitCover.
|
|
func TestImageProcessor_ComputedSideIsAtLeastOne(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputWidth, inputHeight int
|
|
size imagerequest.Size
|
|
wantWidth, wantHeight int
|
|
}{
|
|
{"8192x1 at 100x0", 8192, 1, imagerequest.Size{Width: 100}, 100, 1},
|
|
{"8192x1 at 1300x0", 8192, 1, imagerequest.Size{Width: 1300}, 1300, 1},
|
|
{"8192x2 at 100x0", 8192, 2, imagerequest.Size{Width: 100}, 100, 1},
|
|
{"1x8192 at 0x100", 1, 8192, imagerequest.Size{Height: 100}, 1, 100},
|
|
{"1x8192 at 0x1300", 1, 8192, imagerequest.Size{Height: 1300}, 1, 1300},
|
|
{"2x8192 at 0x100", 2, 8192, imagerequest.Size{Height: 100}, 1, 100},
|
|
}
|
|
|
|
fits := []imagerequest.Fit{
|
|
imagerequest.FitCover, imagerequest.FitContain, imagerequest.FitFill,
|
|
imagerequest.FitInside, imagerequest.FitOutside,
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
for _, fit := range fits {
|
|
t.Run(tt.name+" "+string(fit), func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
width, height, err := targetDimensions(tt.size,
|
|
tt.inputWidth, tt.inputHeight)
|
|
if err != nil || width != tt.wantWidth || height != tt.wantHeight {
|
|
t.Fatalf("targetDimensions() = %dx%d, %v, want %dx%d",
|
|
width, height, err, tt.wantWidth, tt.wantHeight)
|
|
}
|
|
|
|
input := createTestJPEG(t, tt.inputWidth, tt.inputHeight)
|
|
|
|
result, err := New(Params{
|
|
MaxInputBytes: 50 << 20,
|
|
MaxConcurrentProcessing: 1,
|
|
}).Process(t.Context(),
|
|
bytes.NewReader(input), imagerequest.FormatJPEG,
|
|
&imagerequest.Transform{
|
|
Size: tt.size,
|
|
Format: imagerequest.FormatJPEG,
|
|
FitMode: fit,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Process() error = %v", err)
|
|
}
|
|
|
|
defer func() { _ = result.Content.Close() }()
|
|
|
|
t.Logf("Process() made %dx%d", result.Width, result.Height)
|
|
|
|
ok := result.Width == tt.wantWidth && result.Height == tt.wantHeight
|
|
if fit == imagerequest.FitOutside {
|
|
ok = result.Width >= tt.wantWidth && result.Height >= tt.wantHeight
|
|
}
|
|
|
|
if !ok {
|
|
t.Errorf("Process() made %dx%d, want %dx%d (at least, for %s)",
|
|
result.Width, result.Height, tt.wantWidth, tt.wantHeight,
|
|
imagerequest.FitOutside)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|