check / check (push) Canceled after 0s
A size with one side 0 has that side worked out from the source's proportions by integer division, and nothing kept it at 1 or more. When it rounded down to 0, libvips was asked for a square: an 8192x1 source at 100x0 came out 100x100, at 1300x0 it asked for one block of about 39 GB, and some shapes answered 500. Each computed side, and each side contain, inside and outside work out again from the scale, is now at least 1. README.md now says what fit=outside does and what a 0 side means; with fit=outside an 8192x1 source at 100x0 comes out 8192x1, as covering the size requires. Model: opus-5-5
119 lines
3.9 KiB
Go
119 lines
3.9 KiB
Go
package imageprocessor
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// 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 Size
|
|
wantErr error
|
|
}{
|
|
{"width at the maximum", 4096, 1, Size{Height: 2}, nil},
|
|
{"width above the maximum", 4096, 1, Size{Height: 3}, ErrOutputTooLarge},
|
|
{"height at the maximum", 1, 4096, Size{Width: 2}, nil},
|
|
{"height above the maximum", 1, 4096, 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),
|
|
&Request{Size: tt.size, Format: FormatJPEG, FitMode: 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 Size
|
|
wantWidth, wantHeight int
|
|
}{
|
|
{"8192x1 at 100x0", 8192, 1, Size{Width: 100}, 100, 1},
|
|
{"8192x1 at 1300x0", 8192, 1, Size{Width: 1300}, 1300, 1},
|
|
{"8192x2 at 100x0", 8192, 2, Size{Width: 100}, 100, 1},
|
|
{"1x8192 at 0x100", 1, 8192, Size{Height: 100}, 1, 100},
|
|
{"1x8192 at 0x1300", 1, 8192, Size{Height: 1300}, 1, 1300},
|
|
{"2x8192 at 0x100", 2, 8192, Size{Height: 100}, 1, 100},
|
|
}
|
|
|
|
fits := []FitMode{FitCover, FitContain, FitFill, FitInside, 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),
|
|
&Request{Size: tt.size, Format: 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 == 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,
|
|
FitOutside)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|