test: unit tests for content facts, field type request options, variant keys and WebP
- pact: the content kinds and tools, zero facts, the value types - cabana: mergeRequestOptions precedence, one call per type, fail-open, no shared maps - attach: VariantKey on thumbnail names - attach/webp: every image kind, the stored content type, the broken-image thumbnail and a refused mode
This commit is contained in:
51
modules/lagoon/attach/variant_test.go
Normal file
51
modules/lagoon/attach/variant_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package attach
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestVariantKeyTable pins VariantKey beside ThumbKey's names: the
|
||||
// extension is replaced (case-insensitively, the format lower-cased), a key
|
||||
// with the format's extension gets it appended, a key without an extension
|
||||
// gets one, only the last extension counts, and a format outside the token
|
||||
// rule or an empty key answers "". A variant never equals its thumbnail.
|
||||
func TestVariantKeyTable(t *testing.T) {
|
||||
for _, tc := range []struct{ thumb, format, want string }{
|
||||
{"a/b/c/thumb_1_480_0_0_0_auto.jpg", "webp", "a/b/c/thumb_1_480_0_0_0_auto.webp"},
|
||||
{"a/b/c/thumb_1_480_0_0_0_auto.JPG", "webp", "a/b/c/thumb_1_480_0_0_0_auto.webp"},
|
||||
{"a/b/c/thumb_1_480_0_0_0_auto.jpeg", "AVIF", "a/b/c/thumb_1_480_0_0_0_auto.avif"},
|
||||
{"a/b/c/thumb_1_480_0_0_0_auto.WEBP", "webp", "a/b/c/thumb_1_480_0_0_0_auto.WEBP.webp"},
|
||||
{"a/b/c/thumb_1_480_0_0_0_auto.tar.gz", "webp", "a/b/c/thumb_1_480_0_0_0_auto.tar.webp"},
|
||||
{"a/b/c/thumb_1_480_0_0_0_auto", "webp", "a/b/c/thumb_1_480_0_0_0_auto.webp"},
|
||||
{"a/b.c/thumb", "webp", "a/b.c/thumb.webp"},
|
||||
{"a/b/c/thumb_1.jpg", "web p", ""},
|
||||
{"a/b/c/thumb_1.jpg", "webp/", ""},
|
||||
{"a/b/c/thumb_1.jpg", "-", ""},
|
||||
{"", "jpg", ""},
|
||||
} {
|
||||
got := VariantKey(tc.thumb, tc.format)
|
||||
if got != tc.want {
|
||||
t.Errorf("VariantKey(%q, %q) = %q, want %q", tc.thumb, tc.format, got, tc.want)
|
||||
}
|
||||
if got != "" && got == tc.thumb {
|
||||
t.Errorf("VariantKey(%q, %q) overwrites the thumbnail", tc.thumb, tc.format)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestVariantKeyOfThumbFilename pins the variant of a real thumbnail name
|
||||
// (ThumbFilename in the original's partition directory): it keeps the
|
||||
// directory and the stem and differs only in the extension, for an
|
||||
// original of each common format.
|
||||
func TestVariantKeyOfThumbFilename(t *testing.T) {
|
||||
for _, ext := range []string{"jpg", "png", "gif", "webp"} {
|
||||
disk := "abc123def456ghi789jkl0." + ext
|
||||
thumb := PartitionDirectory(disk) + ThumbFilename(42, 480, 320, 0, 0, "exact", ext)
|
||||
got := VariantKey(thumb, "webp")
|
||||
stem := strings.TrimSuffix(thumb, "."+ext)
|
||||
if got == thumb || !strings.HasPrefix(got, stem+".") || !strings.HasSuffix(got, ".webp") || strings.Contains(strings.TrimPrefix(got, stem), "/") {
|
||||
t.Errorf("%s: VariantKey(%q) = %q", disk, thumb, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
115
modules/lagoon/attach/webp/webp_test.go
Normal file
115
modules/lagoon/attach/webp/webp_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package webp_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon/attach"
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon/attach/webp"
|
||||
"gocloud.dev/blob/memblob"
|
||||
)
|
||||
|
||||
// TestEncodeImageKinds pins Encode on the image kinds a decoder hands it:
|
||||
// RGBA, NRGBA, grey, paletted and YCbCr pictures all come out as a WebP of
|
||||
// the same size, and a 1x1 picture too.
|
||||
func TestEncodeImageKinds(t *testing.T) {
|
||||
rgba := gradient(48, 30)
|
||||
nrgba := image.NewNRGBA(rgba.Bounds())
|
||||
draw.Draw(nrgba, nrgba.Bounds(), rgba, image.Point{}, draw.Src)
|
||||
gray := image.NewGray(rgba.Bounds())
|
||||
draw.Draw(gray, gray.Bounds(), rgba, image.Point{}, draw.Src)
|
||||
pal := image.NewPaletted(rgba.Bounds(), color.Palette{color.Black, color.White, color.RGBA{200, 20, 20, 255}})
|
||||
draw.Draw(pal, pal.Bounds(), rgba, image.Point{}, draw.Src)
|
||||
ycc := image.NewYCbCr(rgba.Bounds(), image.YCbCrSubsampleRatio420)
|
||||
one := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
||||
for name, img := range map[string]image.Image{"rgba": rgba, "nrgba": nrgba, "gray": gray, "paletted": pal, "ycbcr": ycc, "1x1": one} {
|
||||
var buf bytes.Buffer
|
||||
if err := webp.Encode(&buf, img); err != nil {
|
||||
t.Fatalf("%s: %v", name, err)
|
||||
}
|
||||
cfg, format, err := image.DecodeConfig(bytes.NewReader(buf.Bytes()))
|
||||
b := img.Bounds()
|
||||
if err != nil || format != "webp" || cfg.Width != b.Dx() || cfg.Height != b.Dy() || !isWebP(buf.Bytes()) {
|
||||
t.Fatalf("%s: decoded %+v %q err=%v, want a %dx%d webp", name, cfg, format, err, b.Dx(), b.Dy())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestEncodeConstants pins the variant's format, content type and quality.
|
||||
func TestEncodeConstants(t *testing.T) {
|
||||
if webp.Format != "webp" || webp.ContentType != "image/webp" || webp.Quality < 1 || webp.Quality > 100 {
|
||||
t.Fatalf("Format %q ContentType %q Quality %d", webp.Format, webp.ContentType, webp.Quality)
|
||||
}
|
||||
}
|
||||
|
||||
// TestVariantStoredWithContentType pins the stored variant's content type
|
||||
// and that the variant key is the thumbnail's VariantKey, and that a
|
||||
// second call answers the same key without touching the stored bytes.
|
||||
func TestVariantStoredWithContentType(t *testing.T) {
|
||||
bucket := memblob.OpenBucket(nil)
|
||||
defer bucket.Close()
|
||||
f := &attach.File{ID: 11, DiskName: "jkl012mno345pqr678stu9.jpg"}
|
||||
putOriginal(t, bucket, f, 320, 200)
|
||||
key, err := webp.Variant(t.Context(), bucket, f, 160, 100, "exact")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
thumb, err := f.ThumbKey(t.Context(), bucket, 160, 100, "exact")
|
||||
if err != nil || key != attach.VariantKey(thumb, webp.Format) {
|
||||
t.Fatalf("key %q, thumbnail %q err=%v", key, thumb, err)
|
||||
}
|
||||
attrs, err := bucket.Attributes(t.Context(), key)
|
||||
if err != nil || attrs.ContentType != webp.ContentType {
|
||||
t.Fatalf("attributes %+v err=%v, want image/webp", attrs, err)
|
||||
}
|
||||
before, _ := bucket.ReadAll(t.Context(), key)
|
||||
again, err := webp.Variant(t.Context(), bucket, f, 160, 100, "exact")
|
||||
after, _ := bucket.ReadAll(t.Context(), key)
|
||||
if err != nil || again != key || !bytes.Equal(before, after) {
|
||||
t.Fatalf("second call %q err=%v, bytes changed %v", again, err, !bytes.Equal(before, after))
|
||||
}
|
||||
}
|
||||
|
||||
// TestVariantBrokenAndRefused pins the edges: a missing original gets
|
||||
// ThumbKey's broken-image thumbnail, whose variant is still a WebP; a mode
|
||||
// outside the token rule is refused and writes no variant.
|
||||
func TestVariantBrokenAndRefused(t *testing.T) {
|
||||
bucket := memblob.OpenBucket(nil)
|
||||
defer bucket.Close()
|
||||
missing := &attach.File{ID: 12, DiskName: "vwx901yza234bcd567efg8.jpg"}
|
||||
key, err := webp.Variant(t.Context(), bucket, missing, 100, 100, "exact")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if raw, err := bucket.ReadAll(t.Context(), key); err != nil || !isWebP(raw) {
|
||||
t.Fatalf("variant of the broken-image thumbnail %q: err=%v", key, err)
|
||||
}
|
||||
good := &attach.File{ID: 14, DiskName: "tuv345wxy678zab901cde2.jpg"}
|
||||
putOriginal(t, bucket, good, 200, 200)
|
||||
if _, err := webp.Variant(t.Context(), bucket, good, 100, 100, "../x"); err == nil {
|
||||
t.Fatal("a mode outside the token rule must fail")
|
||||
}
|
||||
iter := bucket.List(nil)
|
||||
webps := 0
|
||||
for {
|
||||
obj, err := iter.Next(t.Context())
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.HasSuffix(obj.Key, ".webp") {
|
||||
webps++
|
||||
}
|
||||
}
|
||||
if webps != 1 {
|
||||
t.Fatalf("%d WebP files in the bucket, want only the broken-image variant", webps)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user