github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/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/gohugoio/hugo/htesting/hqt"
    25  	"github.com/google/go-cmp/cmp"
    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  
    62  	c.Assert(x2, eq, x)
    63  }
    64  
    65  func TestExifPNG(t *testing.T) {
    66  	c := qt.New(t)
    67  
    68  	f, err := os.Open(filepath.FromSlash("../../testdata/gohugoio.png"))
    69  	c.Assert(err, qt.IsNil)
    70  	defer f.Close()
    71  
    72  	d, err := NewDecoder()
    73  	c.Assert(err, qt.IsNil)
    74  	_, err = d.Decode(f)
    75  	c.Assert(err, qt.Not(qt.IsNil))
    76  }
    77  
    78  func TestIssue8079(t *testing.T) {
    79  	c := qt.New(t)
    80  
    81  	f, err := os.Open(filepath.FromSlash("../../testdata/iss8079.jpg"))
    82  	c.Assert(err, qt.IsNil)
    83  	defer f.Close()
    84  
    85  	d, err := NewDecoder()
    86  	c.Assert(err, qt.IsNil)
    87  	x, err := d.Decode(f)
    88  	c.Assert(err, qt.IsNil)
    89  	c.Assert(x.Tags["ImageDescription"], qt.Equals, "Città del Vaticano #nanoblock #vatican #vaticancity")
    90  }
    91  
    92  func TestNullString(t *testing.T) {
    93  	c := qt.New(t)
    94  
    95  	for _, test := range []struct {
    96  		in     string
    97  		expect string
    98  	}{
    99  		{"foo", "foo"},
   100  		{"\x20", "\x20"},
   101  		{"\xc4\x81", "\xc4\x81"}, // \u0101
   102  		{"\u0160", "\u0160"},     // non-breaking space
   103  	} {
   104  		res := nullString([]byte(test.in))
   105  		c.Assert(res, qt.Equals, test.expect)
   106  	}
   107  }
   108  
   109  func BenchmarkDecodeExif(b *testing.B) {
   110  	c := qt.New(b)
   111  	f, err := os.Open(filepath.FromSlash("../../testdata/sunset.jpg"))
   112  	c.Assert(err, qt.IsNil)
   113  	defer f.Close()
   114  
   115  	d, err := NewDecoder()
   116  	c.Assert(err, qt.IsNil)
   117  
   118  	b.ResetTimer()
   119  	for i := 0; i < b.N; i++ {
   120  		_, err = d.Decode(f)
   121  		c.Assert(err, qt.IsNil)
   122  		f.Seek(0, 0)
   123  	}
   124  }
   125  
   126  var eq = qt.CmpEquals(
   127  	cmp.Comparer(
   128  		func(v1, v2 *big.Rat) bool {
   129  			return v1.RatString() == v2.RatString()
   130  		},
   131  	),
   132  	cmp.Comparer(func(v1, v2 time.Time) bool {
   133  		return v1.Unix() == v2.Unix()
   134  	}),
   135  )
   136  
   137  func TestIssue10738(t *testing.T) {
   138  
   139  	c := qt.New(t)
   140  
   141  	testFunc := func(path, include string) any {
   142  		f, err := os.Open(filepath.FromSlash(path))
   143  		c.Assert(err, qt.IsNil)
   144  		defer f.Close()
   145  
   146  		d, err := NewDecoder(IncludeFields(include))
   147  		c.Assert(err, qt.IsNil)
   148  		x, err := d.Decode(f)
   149  		c.Assert(err, qt.IsNil)
   150  
   151  		// Verify that it survives a round-trip to JSON and back.
   152  		data, err := json.Marshal(x)
   153  		c.Assert(err, qt.IsNil)
   154  		x2 := &ExifInfo{}
   155  		err = json.Unmarshal(data, x2)
   156  
   157  		c.Assert(x2, eq, x)
   158  
   159  		v, found := x.Tags["ExposureTime"]
   160  		c.Assert(found, qt.Equals, true)
   161  		return v
   162  	}
   163  
   164  	type args struct {
   165  		path    string // imagePath
   166  		include string // includeFields
   167  	}
   168  
   169  	type want struct {
   170  		vN int64 // numerator
   171  		vD int64 // denominator
   172  	}
   173  
   174  	type testCase struct {
   175  		name string
   176  		args args
   177  		want want
   178  	}
   179  
   180  	tests := []testCase{
   181  		{
   182  			"canon_cr2_fraction", args{
   183  				path:    "../../testdata/issue10738/canon_cr2_fraction.jpg",
   184  				include: "Lens|Date|ExposureTime",
   185  			}, want{
   186  				1,
   187  				500,
   188  			},
   189  		},
   190  		{
   191  			"canon_cr2_integer", args{
   192  				path:    "../../testdata/issue10738/canon_cr2_integer.jpg",
   193  				include: "Lens|Date|ExposureTime",
   194  			}, want{
   195  				10,
   196  				0,
   197  			},
   198  		},
   199  		{
   200  			"dji_dng_fraction", args{
   201  				path:    "../../testdata/issue10738/dji_dng_fraction.jpg",
   202  				include: "Lens|Date|ExposureTime",
   203  			}, want{
   204  				1,
   205  				4000,
   206  			},
   207  		},
   208  		{
   209  			"fuji_raf_fraction", args{
   210  				path:    "../../testdata/issue10738/fuji_raf_fraction.jpg",
   211  				include: "Lens|Date|ExposureTime",
   212  			}, want{
   213  				1,
   214  				250,
   215  			},
   216  		},
   217  		{
   218  			"fuji_raf_integer", args{
   219  				path:    "../../testdata/issue10738/fuji_raf_integer.jpg",
   220  				include: "Lens|Date|ExposureTime",
   221  			}, want{
   222  				1,
   223  				0,
   224  			},
   225  		},
   226  		{
   227  			"leica_dng_fraction", args{
   228  				path:    "../../testdata/issue10738/leica_dng_fraction.jpg",
   229  				include: "Lens|Date|ExposureTime",
   230  			}, want{
   231  				1,
   232  				100,
   233  			},
   234  		},
   235  		{
   236  			"lumix_rw2_fraction", args{
   237  				path:    "../../testdata/issue10738/lumix_rw2_fraction.jpg",
   238  				include: "Lens|Date|ExposureTime",
   239  			}, want{
   240  				1,
   241  				400,
   242  			},
   243  		},
   244  		{
   245  			"nikon_nef_d5600", args{
   246  				path:    "../../testdata/issue10738/nikon_nef_d5600.jpg",
   247  				include: "Lens|Date|ExposureTime",
   248  			}, want{
   249  				1,
   250  				1000,
   251  			},
   252  		},
   253  		{
   254  			"nikon_nef_fraction", args{
   255  				path:    "../../testdata/issue10738/nikon_nef_fraction.jpg",
   256  				include: "Lens|Date|ExposureTime",
   257  			}, want{
   258  				1,
   259  				640,
   260  			},
   261  		},
   262  		{
   263  			"nikon_nef_integer", args{
   264  				path:    "../../testdata/issue10738/nikon_nef_integer.jpg",
   265  				include: "Lens|Date|ExposureTime",
   266  			}, want{
   267  				30,
   268  				0,
   269  			},
   270  		},
   271  		{
   272  			"nikon_nef_fraction_2", args{
   273  				path:    "../../testdata/issue10738/nikon_nef_fraction_2.jpg",
   274  				include: "Lens|Date|ExposureTime",
   275  			}, want{
   276  				1,
   277  				6400,
   278  			},
   279  		},
   280  		{
   281  			"sony_arw_fraction", args{
   282  				path:    "../../testdata/issue10738/sony_arw_fraction.jpg",
   283  				include: "Lens|Date|ExposureTime",
   284  			}, want{
   285  				1,
   286  				160,
   287  			},
   288  		},
   289  		{
   290  			"sony_arw_integer", args{
   291  				path:    "../../testdata/issue10738/sony_arw_integer.jpg",
   292  				include: "Lens|Date|ExposureTime",
   293  			}, want{
   294  				4,
   295  				0,
   296  			},
   297  		},
   298  	}
   299  
   300  	for _, tt := range tests {
   301  		c.Run(tt.name, func(c *qt.C) {
   302  			got := testFunc(tt.args.path, tt.args.include)
   303  			switch got.(type) {
   304  			case float64:
   305  				eTime, ok := got.(float64)
   306  				c.Assert(ok, qt.Equals, true)
   307  				c.Assert(eTime, qt.Equals, float64(tt.want.vN))
   308  			case *big.Rat:
   309  				eTime, ok := got.(*big.Rat)
   310  				c.Assert(ok, qt.Equals, true)
   311  				c.Assert(eTime, eq, big.NewRat(tt.want.vN, tt.want.vD))
   312  			}
   313  		})
   314  	}
   315  }