github.com/neohugo/neohugo@v0.123.8/resources/images/exif/exif_test.go (about) 1 // Copyright 2019 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package exif 15 16 import ( 17 "encoding/json" 18 "math/big" 19 "os" 20 "path/filepath" 21 "testing" 22 "time" 23 24 "github.com/google/go-cmp/cmp" 25 "github.com/neohugo/neohugo/htesting/hqt" 26 27 qt "github.com/frankban/quicktest" 28 ) 29 30 func TestExif(t *testing.T) { 31 c := qt.New(t) 32 f, err := os.Open(filepath.FromSlash("../../testdata/sunset.jpg")) 33 c.Assert(err, qt.IsNil) 34 defer f.Close() 35 36 d, err := NewDecoder(IncludeFields("Lens|Date")) 37 c.Assert(err, qt.IsNil) 38 x, err := d.Decode(f) 39 c.Assert(err, qt.IsNil) 40 c.Assert(x.Date.Format("2006-01-02"), qt.Equals, "2017-10-27") 41 42 // Malaga: https://goo.gl/taazZy 43 c.Assert(x.Lat, qt.Equals, float64(36.59744166666667)) 44 c.Assert(x.Long, qt.Equals, float64(-4.50846)) 45 46 v, found := x.Tags["LensModel"] 47 c.Assert(found, qt.Equals, true) 48 lensModel, ok := v.(string) 49 c.Assert(ok, qt.Equals, true) 50 c.Assert(lensModel, qt.Equals, "smc PENTAX-DA* 16-50mm F2.8 ED AL [IF] SDM") 51 52 v, found = x.Tags["DateTime"] 53 c.Assert(found, qt.Equals, true) 54 c.Assert(v, hqt.IsSameType, time.Time{}) 55 56 // Verify that it survives a round-trip to JSON and back. 57 data, err := json.Marshal(x) 58 c.Assert(err, qt.IsNil) 59 x2 := &ExifInfo{} 60 err = json.Unmarshal(data, x2) 61 c.Assert(err, qt.IsNil) 62 63 c.Assert(x2, eq, x) 64 } 65 66 func TestExifPNG(t *testing.T) { 67 c := qt.New(t) 68 69 f, err := os.Open(filepath.FromSlash("../../testdata/gohugoio.png")) 70 c.Assert(err, qt.IsNil) 71 defer f.Close() 72 73 d, err := NewDecoder() 74 c.Assert(err, qt.IsNil) 75 _, err = d.Decode(f) 76 c.Assert(err, qt.Not(qt.IsNil)) 77 } 78 79 func TestIssue8079(t *testing.T) { 80 c := qt.New(t) 81 82 f, err := os.Open(filepath.FromSlash("../../testdata/iss8079.jpg")) 83 c.Assert(err, qt.IsNil) 84 defer f.Close() 85 86 d, err := NewDecoder() 87 c.Assert(err, qt.IsNil) 88 x, err := d.Decode(f) 89 c.Assert(err, qt.IsNil) 90 c.Assert(x.Tags["ImageDescription"], qt.Equals, "Città del Vaticano #nanoblock #vatican #vaticancity") 91 } 92 93 func TestNullString(t *testing.T) { 94 c := qt.New(t) 95 96 for _, test := range []struct { 97 in string 98 expect string 99 }{ 100 {"foo", "foo"}, 101 {"\x20", "\x20"}, 102 {"\xc4\x81", "\xc4\x81"}, // \u0101 103 {"\u0160", "\u0160"}, // non-breaking space 104 } { 105 res := nullString([]byte(test.in)) 106 c.Assert(res, qt.Equals, test.expect) 107 } 108 } 109 110 func BenchmarkDecodeExif(b *testing.B) { 111 c := qt.New(b) 112 f, err := os.Open(filepath.FromSlash("../../testdata/sunset.jpg")) 113 c.Assert(err, qt.IsNil) 114 defer f.Close() 115 116 d, err := NewDecoder() 117 c.Assert(err, qt.IsNil) 118 119 b.ResetTimer() 120 for i := 0; i < b.N; i++ { 121 _, err = d.Decode(f) 122 c.Assert(err, qt.IsNil) 123 _, err = f.Seek(0, 0) 124 c.Assert(err, qt.IsNil) 125 } 126 } 127 128 var eq = qt.CmpEquals( 129 cmp.Comparer( 130 func(v1, v2 *big.Rat) bool { 131 return v1.RatString() == v2.RatString() 132 }, 133 ), 134 cmp.Comparer(func(v1, v2 time.Time) bool { 135 return v1.Unix() == v2.Unix() 136 }), 137 ) 138 139 func TestIssue10738(t *testing.T) { 140 c := qt.New(t) 141 142 testFunc := func(path, include string) any { 143 f, err := os.Open(filepath.FromSlash(path)) 144 c.Assert(err, qt.IsNil) 145 defer f.Close() 146 147 d, err := NewDecoder(IncludeFields(include)) 148 c.Assert(err, qt.IsNil) 149 x, err := d.Decode(f) 150 c.Assert(err, qt.IsNil) 151 152 // Verify that it survives a round-trip to JSON and back. 153 data, err := json.Marshal(x) 154 c.Assert(err, qt.IsNil) 155 x2 := &ExifInfo{} 156 err = json.Unmarshal(data, x2) 157 c.Assert(err, qt.IsNil) 158 159 c.Assert(x2, eq, x) 160 161 v, found := x.Tags["ExposureTime"] 162 c.Assert(found, qt.Equals, true) 163 return v 164 } 165 166 type args struct { 167 path string // imagePath 168 include string // includeFields 169 } 170 171 type want struct { 172 vN int64 // numerator 173 vD int64 // denominator 174 } 175 176 type testCase struct { 177 name string 178 args args 179 want want 180 } 181 182 tests := []testCase{ 183 { 184 "canon_cr2_fraction", args{ 185 path: "../../testdata/issue10738/canon_cr2_fraction.jpg", 186 include: "Lens|Date|ExposureTime", 187 }, want{ 188 1, 189 500, 190 }, 191 }, 192 { 193 "canon_cr2_integer", args{ 194 path: "../../testdata/issue10738/canon_cr2_integer.jpg", 195 include: "Lens|Date|ExposureTime", 196 }, want{ 197 10, 198 0, 199 }, 200 }, 201 { 202 "dji_dng_fraction", args{ 203 path: "../../testdata/issue10738/dji_dng_fraction.jpg", 204 include: "Lens|Date|ExposureTime", 205 }, want{ 206 1, 207 4000, 208 }, 209 }, 210 { 211 "fuji_raf_fraction", args{ 212 path: "../../testdata/issue10738/fuji_raf_fraction.jpg", 213 include: "Lens|Date|ExposureTime", 214 }, want{ 215 1, 216 250, 217 }, 218 }, 219 { 220 "fuji_raf_integer", args{ 221 path: "../../testdata/issue10738/fuji_raf_integer.jpg", 222 include: "Lens|Date|ExposureTime", 223 }, want{ 224 1, 225 0, 226 }, 227 }, 228 { 229 "leica_dng_fraction", args{ 230 path: "../../testdata/issue10738/leica_dng_fraction.jpg", 231 include: "Lens|Date|ExposureTime", 232 }, want{ 233 1, 234 100, 235 }, 236 }, 237 { 238 "lumix_rw2_fraction", args{ 239 path: "../../testdata/issue10738/lumix_rw2_fraction.jpg", 240 include: "Lens|Date|ExposureTime", 241 }, want{ 242 1, 243 400, 244 }, 245 }, 246 { 247 "nikon_nef_d5600", args{ 248 path: "../../testdata/issue10738/nikon_nef_d5600.jpg", 249 include: "Lens|Date|ExposureTime", 250 }, want{ 251 1, 252 1000, 253 }, 254 }, 255 { 256 "nikon_nef_fraction", args{ 257 path: "../../testdata/issue10738/nikon_nef_fraction.jpg", 258 include: "Lens|Date|ExposureTime", 259 }, want{ 260 1, 261 640, 262 }, 263 }, 264 { 265 "nikon_nef_integer", args{ 266 path: "../../testdata/issue10738/nikon_nef_integer.jpg", 267 include: "Lens|Date|ExposureTime", 268 }, want{ 269 30, 270 0, 271 }, 272 }, 273 { 274 "nikon_nef_fraction_2", args{ 275 path: "../../testdata/issue10738/nikon_nef_fraction_2.jpg", 276 include: "Lens|Date|ExposureTime", 277 }, want{ 278 1, 279 6400, 280 }, 281 }, 282 { 283 "sony_arw_fraction", args{ 284 path: "../../testdata/issue10738/sony_arw_fraction.jpg", 285 include: "Lens|Date|ExposureTime", 286 }, want{ 287 1, 288 160, 289 }, 290 }, 291 { 292 "sony_arw_integer", args{ 293 path: "../../testdata/issue10738/sony_arw_integer.jpg", 294 include: "Lens|Date|ExposureTime", 295 }, want{ 296 4, 297 0, 298 }, 299 }, 300 } 301 302 for _, tt := range tests { 303 c.Run(tt.name, func(c *qt.C) { 304 got := testFunc(tt.args.path, tt.args.include) 305 switch v := got.(type) { 306 case float64: 307 c.Assert(v, qt.Equals, float64(tt.want.vN)) 308 case *big.Rat: 309 c.Assert(v, eq, big.NewRat(tt.want.vN, tt.want.vD)) 310 default: 311 c.Fatalf("unexpected type: %T", got) 312 } 313 }) 314 } 315 }