package format import ( "bytes" "fmt" "image/jpeg" "os/exec" "path/filepath" "strings" "testing" "time" ) func requireTools(t *testing.T) { t.Helper() if err := CheckTools(); err != nil { t.Skip(err) } } func makeImage(t *testing.T, name string, w, h int) string { t.Helper() p := filepath.Join(t.TempDir(), name) run(t, "magick", "-size", fmt.Sprintf("%dx%d", w, h), "xc:gray", p) return p } func run(t *testing.T, name string, args ...string) { t.Helper() if out, err := exec.Command(name, args...).CombinedOutput(); err != nil { t.Fatalf("%s %v: %v\n%s", name, args, err, out) } } func resizedSize(t *testing.T, f Format, src string, w int) (int, int) { t.Helper() var buf bytes.Buffer if err := f.Resize(src, w, &buf); err != nil { t.Fatal(err) } cfg, err := jpeg.DecodeConfig(&buf) if err != nil { t.Fatalf("output is not JPEG: %v", err) } return cfg.Width, cfg.Height } func TestMagickJPEG(t *testing.T) { requireTools(t) p := makeImage(t, "a.jpg", 300, 200) run(t, "exiftool", "-overwrite_original", "-DateTimeOriginal=2025:03:14 23:10:05", "-Model=TestCam", p) f := NewMagick("jpeg", ".jpg", ".jpeg") m, err := f.Metadata(p) if err != nil { t.Fatal(err) } if m.Width != 300 || m.Height != 200 || m.Camera != "TestCam" { t.Fatalf("got %+v", m) } if want := time.Date(2025, 3, 14, 23, 10, 5, 0, time.UTC); !m.Taken.Equal(want) { t.Fatalf("Taken = %v", m.Taken) } if w, h := resizedSize(t, f, p, 150); w != 150 || h != 100 { t.Fatalf("resized to %dx%d, want 150x100", w, h) } } func TestMagickOrientation(t *testing.T) { requireTools(t) p := makeImage(t, "r.jpg", 300, 200) run(t, "exiftool", "-overwrite_original", "-n", "-Orientation=6", p) f := NewMagick("jpeg", ".jpg") m, err := f.Metadata(p) if err != nil { t.Fatal(err) } if m.Width != 200 || m.Height != 300 { t.Fatalf("metadata %dx%d, want 200x300", m.Width, m.Height) } if w, h := resizedSize(t, f, p, 100); w != 100 || h != 150 { t.Fatalf("resized to %dx%d, want 100x150", w, h) } } func TestMagickPNG(t *testing.T) { requireTools(t) p := makeImage(t, "a.png", 120, 80) f := NewMagick("png", ".png") m, err := f.Metadata(p) if err != nil { t.Fatal(err) } if m.Width != 120 || m.Height != 80 { t.Fatalf("got %+v", m) } if w, h := resizedSize(t, f, p, 60); w != 60 || h != 40 { t.Fatalf("resized to %dx%d, want 60x40", w, h) } } func TestMagickResizeError(t *testing.T) { requireTools(t) var buf bytes.Buffer if err := NewMagick("jpeg", ".jpg").Resize(filepath.Join(t.TempDir(), "missing.jpg"), 100, &buf); err == nil { t.Fatal("want error") } } func TestDefaultRegistry(t *testing.T) { r := Default() for path, want := range map[string]string{"a.JPG": "jpeg", "a.jpeg": "jpeg", "a.png": "png"} { if f := r.Lookup(path); f == nil || f.Name() != want { t.Errorf("%s: got %v, want %s", path, f, want) } } if r.Lookup("a.heic") != nil { t.Error("heic should not match in v1") } } func TestMagickMetadataManyFiles(t *testing.T) { requireTools(t) f := NewMagick("jpeg", ".jpg") dir := t.TempDir() before := exiftoolStarts.Load() for i := 1; i <= 20; i++ { p := filepath.Join(dir, fmt.Sprintf("%02d.jpg", i)) run(t, "magick", "-size", fmt.Sprintf("%dx10", i*10), "xc:gray", p) if i == 10 { if _, err := f.Metadata(filepath.Join(dir, "missing.jpg")); err == nil { t.Fatal("missing file: want error") } } m, err := f.Metadata(p) if err != nil { t.Fatalf("%s: %v", p, err) } if m.Width != i*10 || m.Height != 10 { t.Fatalf("%s: got %dx%d, want %dx10", p, m.Width, m.Height, i*10) } } if n := exiftoolStarts.Load() - before; n > 1 { t.Fatalf("started exiftool %d times for 21 calls, want at most 1", n) } } func TestMagickMetadataRejectsNewlineInPath(t *testing.T) { if _, err := NewMagick("jpeg", ".jpg").Metadata("a\nb.jpg"); err == nil { t.Fatal("want error") } } func TestResizeArgsLimitResources(t *testing.T) { got := strings.Join(resizeArgs("/p/a.jpg", 960), " ") want := "-limit memory 512MiB -limit map 1GiB /p/a.jpg -auto-orient -resize 960x -strip -quality 82 jpg:-" if got != want { t.Fatalf("got %s\nwant %s", got, want) } } func TestMagickMetadataRelativePathArgfileSafe(t *testing.T) { requireTools(t) dir := t.TempDir() run(t, "magick", "-size", "30x20", "xc:gray", filepath.Join(dir, "#a.jpg")) t.Chdir(dir) m, err := NewMagick("jpeg", ".jpg").Metadata("#a.jpg") if err != nil { t.Fatal(err) } if m.Width != 30 || m.Height != 20 { t.Fatalf("got %dx%d", m.Width, m.Height) } }