internal/format/exif_test.go
95 lines · 2552 bytes
1package format
2
3import (
4 "testing"
5 "time"
6)
7
8func TestParseExifFull(t *testing.T) {
9 data := []byte(`[{
10 "SourceFile": "a.jpg",
11 "ImageWidth": 6240, "ImageHeight": 4160, "Orientation": 1,
12 "DateTimeOriginal": "2025:03:14 23:10:05",
13 "Make": "FUJIFILM", "Model": "X-T5", "LensModel": "XF23mmF2 R WR",
14 "FNumber": 2, "ExposureTime": 0.008, "ISO": 1600
15 }]`)
16 m, err := parseExif(data)
17 if err != nil {
18 t.Fatal(err)
19 }
20 want := Meta{
21 Width: 6240, Height: 4160,
22 Taken: time.Date(2025, 3, 14, 23, 10, 5, 0, time.UTC),
23 Camera: "FUJIFILM X-T5",
24 Lens: "XF23mmF2 R WR",
25 Aperture: "f/2",
26 Shutter: "1/125",
27 ISO: 1600,
28 }
29 if m != want {
30 t.Fatalf("got %+v\nwant %+v", m, want)
31 }
32}
33
34func TestParseExifRotatedSwapsDimensions(t *testing.T) {
35 for _, o := range []string{"5", "6", "7", "8"} {
36 m, err := parseExif([]byte(`[{"ImageWidth": 300, "ImageHeight": 200, "Orientation": ` + o + `}]`))
37 if err != nil {
38 t.Fatal(err)
39 }
40 if m.Width != 200 || m.Height != 300 {
41 t.Errorf("orientation %s: got %dx%d, want 200x300", o, m.Width, m.Height)
42 }
43 }
44}
45
46func TestParseExifFallbacks(t *testing.T) {
47 m, err := parseExif([]byte(`[{
48 "ImageWidth": 10, "ImageHeight": 10,
49 "CreateDate": "2024:01:02 03:04:05+01:00",
50 "Make": "Canon", "Model": "Canon EOS R6",
51 "FNumber": 5.6, "ExposureTime": 2
52 }]`))
53 if err != nil {
54 t.Fatal(err)
55 }
56 if want := time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC); !m.Taken.Equal(want) {
57 t.Errorf("Taken = %v, want %v", m.Taken, want)
58 }
59 if m.Camera != "Canon EOS R6" {
60 t.Errorf("Camera = %q", m.Camera)
61 }
62 if m.Aperture != "f/5.6" || m.Shutter != "2s" {
63 t.Errorf("Aperture %q Shutter %q", m.Aperture, m.Shutter)
64 }
65}
66
67func TestParseExifMinimal(t *testing.T) {
68 m, err := parseExif([]byte(`[{"ImageWidth": 120, "ImageHeight": 80}]`))
69 if err != nil {
70 t.Fatal(err)
71 }
72 if (m != Meta{Width: 120, Height: 80}) {
73 t.Fatalf("got %+v", m)
74 }
75}
76
77func TestParseExifErrors(t *testing.T) {
78 for _, in := range []string{`not json`, `[]`, `[{}, {}]`, `[{"ImageWidth": 10}]`} {
79 if _, err := parseExif([]byte(in)); err == nil {
80 t.Errorf("%s: want error", in)
81 }
82 }
83}
84
85func TestParseExifRoundsAperture(t *testing.T) {
86 for in, want := range map[string]string{"1.779999971": "f/1.8", "2": "f/2", "5.6": "f/5.6", "11": "f/11", "22": "f/22", "0.95": "f/0.95"} {
87 m, err := parseExif([]byte(`[{"ImageWidth": 1, "ImageHeight": 1, "FNumber": ` + in + `}]`))
88 if err != nil {
89 t.Fatal(err)
90 }
91 if m.Aperture != want {
92 t.Errorf("FNumber %s: got %q, want %q", in, m.Aperture, want)
93 }
94 }
95}