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  }