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
136 lines
4.3 KiB
Go
136 lines
4.3 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{}).Process(t.Context(),
|
|
bytes.NewReader(input),
|
|
&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{}).Process(t.Context(),
|
|
bytes.NewReader(input),
|
|
&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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|