github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/resource/image_test.go (about)

     1  // Copyright 2017-present 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 resource
    15  
    16  import (
    17  	"fmt"
    18  	"math/rand"
    19  	"os"
    20  	"path/filepath"
    21  	"strconv"
    22  	"testing"
    23  
    24  	"github.com/disintegration/imaging"
    25  
    26  	"sync"
    27  
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestParseImageConfig(t *testing.T) {
    32  	for i, this := range []struct {
    33  		in     string
    34  		expect interface{}
    35  	}{
    36  		{"300x400", newImageConfig(300, 400, 0, 0, "", "")},
    37  		{"100x200 bottomRight", newImageConfig(100, 200, 0, 0, "", "BottomRight")},
    38  		{"10x20 topleft Lanczos", newImageConfig(10, 20, 0, 0, "Lanczos", "topleft")},
    39  		{"linear left 10x r180", newImageConfig(10, 0, 0, 180, "linear", "left")},
    40  		{"x20 riGht Cosine q95", newImageConfig(0, 20, 95, 0, "cosine", "right")},
    41  
    42  		{"", false},
    43  		{"foo", false},
    44  	} {
    45  		result, err := parseImageConfig(this.in)
    46  		if b, ok := this.expect.(bool); ok && !b {
    47  			if err == nil {
    48  				t.Errorf("[%d] parseImageConfig didn't return an expected error", i)
    49  			}
    50  		} else {
    51  			if err != nil {
    52  				t.Fatalf("[%d] err: %s", i, err)
    53  			}
    54  			if fmt.Sprint(result) != fmt.Sprint(this.expect) {
    55  				t.Fatalf("[%d] got\n%v\n but expected\n%v", i, result, this.expect)
    56  			}
    57  		}
    58  	}
    59  }
    60  
    61  func TestImageTransformBasic(t *testing.T) {
    62  
    63  	assert := require.New(t)
    64  
    65  	image := fetchSunset(assert)
    66  
    67  	printFs(image.sourceFs(), "", os.Stdout)
    68  
    69  	assert.Equal("/a/sunset.jpg", image.RelPermalink())
    70  	assert.Equal("image", image.ResourceType())
    71  
    72  	resized, err := image.Resize("300x200")
    73  	assert.NoError(err)
    74  	assert.True(image != resized)
    75  	assert.True(image.genericResource != resized.genericResource)
    76  
    77  	resized0x, err := image.Resize("x200")
    78  	assert.NoError(err)
    79  	assert.Equal(320, resized0x.Width())
    80  	assert.Equal(200, resized0x.Height())
    81  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, resized0x.RelPermalink(), 320, 200)
    82  
    83  	resizedx0, err := image.Resize("200x")
    84  	assert.NoError(err)
    85  	assert.Equal(200, resizedx0.Width())
    86  	assert.Equal(125, resizedx0.Height())
    87  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, resizedx0.RelPermalink(), 200, 125)
    88  
    89  	resizedAndRotated, err := image.Resize("x200 r90")
    90  	assert.NoError(err)
    91  	assert.Equal(125, resizedAndRotated.Width())
    92  	assert.Equal(200, resizedAndRotated.Height())
    93  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, resizedAndRotated.RelPermalink(), 125, 200)
    94  
    95  	assert.Equal("/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_300x200_resize_q68_linear.jpg", resized.RelPermalink())
    96  	assert.Equal(300, resized.Width())
    97  	assert.Equal(200, resized.Height())
    98  
    99  	fitted, err := resized.Fit("50x50")
   100  	assert.NoError(err)
   101  	assert.Equal("/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_625708021e2bb281c9f1002f88e4753f.jpg", fitted.RelPermalink())
   102  	assert.Equal(50, fitted.Width())
   103  	assert.Equal(31, fitted.Height())
   104  
   105  	// Check the MD5 key threshold
   106  	fittedAgain, _ := fitted.Fit("10x20")
   107  	fittedAgain, err = fittedAgain.Fit("10x20")
   108  	assert.NoError(err)
   109  	assert.Equal("/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_3f65ba24dc2b7fba0f56d7f104519157.jpg", fittedAgain.RelPermalink())
   110  	assert.Equal(10, fittedAgain.Width())
   111  	assert.Equal(6, fittedAgain.Height())
   112  
   113  	filled, err := image.Fill("200x100 bottomLeft")
   114  	assert.NoError(err)
   115  	assert.Equal("/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x100_fill_q68_linear_bottomleft.jpg", filled.RelPermalink())
   116  	assert.Equal(200, filled.Width())
   117  	assert.Equal(100, filled.Height())
   118  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, filled.RelPermalink(), 200, 100)
   119  
   120  	smart, err := image.Fill("200x100 smart")
   121  	assert.NoError(err)
   122  	assert.Equal(fmt.Sprintf("/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x100_fill_q68_linear_smart%d.jpg", smartCropVersionNumber), smart.RelPermalink())
   123  	assert.Equal(200, smart.Width())
   124  	assert.Equal(100, smart.Height())
   125  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, smart.RelPermalink(), 200, 100)
   126  
   127  	// Check cache
   128  	filledAgain, err := image.Fill("200x100 bottomLeft")
   129  	assert.NoError(err)
   130  	assert.True(filled == filledAgain)
   131  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, filledAgain.RelPermalink(), 200, 100)
   132  
   133  }
   134  
   135  // https://github.com/gohugoio/hugo/issues/4261
   136  func TestImageTransformLongFilename(t *testing.T) {
   137  	assert := require.New(t)
   138  
   139  	image := fetchImage(assert, "1234567890qwertyuiopasdfghjklzxcvbnm5to6eeeeee7via8eleph.jpg")
   140  	assert.NotNil(image)
   141  
   142  	resized, err := image.Resize("200x")
   143  	assert.NoError(err)
   144  	assert.NotNil(resized)
   145  	assert.Equal(200, resized.Width())
   146  	assert.Equal("/a/_hu59e56ffff1bc1d8d122b1403d34e039f_90587_65b757a6e14debeae720fe8831f0a9bc.jpg", resized.RelPermalink())
   147  	resized, err = resized.Resize("100x")
   148  	assert.NoError(err)
   149  	assert.NotNil(resized)
   150  	assert.Equal(100, resized.Width())
   151  	assert.Equal("/a/_hu59e56ffff1bc1d8d122b1403d34e039f_90587_c876768085288f41211f768147ba2647.jpg", resized.RelPermalink())
   152  }
   153  
   154  func TestImageTransformConcurrent(t *testing.T) {
   155  
   156  	var wg sync.WaitGroup
   157  
   158  	assert := require.New(t)
   159  
   160  	spec := newTestResourceOsFs(assert)
   161  
   162  	image := fetchImageForSpec(spec, assert, "sunset.jpg")
   163  
   164  	for i := 0; i < 4; i++ {
   165  		wg.Add(1)
   166  		go func(id int) {
   167  			defer wg.Done()
   168  			for j := 0; j < 5; j++ {
   169  				img := image
   170  				for k := 0; k < 2; k++ {
   171  					r1, err := img.Resize(fmt.Sprintf("%dx", id-k))
   172  					if err != nil {
   173  						t.Fatal(err)
   174  					}
   175  
   176  					if r1.Width() != id-k {
   177  						t.Fatalf("Width: %d:%d", r1.Width(), j)
   178  					}
   179  
   180  					r2, err := r1.Resize(fmt.Sprintf("%dx", id-k-1))
   181  					if err != nil {
   182  						t.Fatal(err)
   183  					}
   184  
   185  					_, err = r2.decodeSource()
   186  					if err != nil {
   187  						t.Fatal("Err decode:", err)
   188  					}
   189  
   190  					img = r1
   191  				}
   192  			}
   193  		}(i + 20)
   194  	}
   195  
   196  	wg.Wait()
   197  }
   198  
   199  func TestDecodeImaging(t *testing.T) {
   200  	assert := require.New(t)
   201  	m := map[string]interface{}{
   202  		"quality":        42,
   203  		"resampleFilter": "NearestNeighbor",
   204  		"anchor":         "topLeft",
   205  	}
   206  
   207  	imaging, err := decodeImaging(m)
   208  
   209  	assert.NoError(err)
   210  	assert.Equal(42, imaging.Quality)
   211  	assert.Equal("nearestneighbor", imaging.ResampleFilter)
   212  	assert.Equal("topleft", imaging.Anchor)
   213  
   214  	m = map[string]interface{}{}
   215  
   216  	imaging, err = decodeImaging(m)
   217  	assert.NoError(err)
   218  	assert.Equal(defaultJPEGQuality, imaging.Quality)
   219  	assert.Equal("box", imaging.ResampleFilter)
   220  	assert.Equal("smart", imaging.Anchor)
   221  
   222  	_, err = decodeImaging(map[string]interface{}{
   223  		"quality": 123,
   224  	})
   225  	assert.Error(err)
   226  
   227  	_, err = decodeImaging(map[string]interface{}{
   228  		"resampleFilter": "asdf",
   229  	})
   230  	assert.Error(err)
   231  
   232  	_, err = decodeImaging(map[string]interface{}{
   233  		"anchor": "asdf",
   234  	})
   235  	assert.Error(err)
   236  
   237  	imaging, err = decodeImaging(map[string]interface{}{
   238  		"anchor": "Smart",
   239  	})
   240  	assert.NoError(err)
   241  	assert.Equal("smart", imaging.Anchor)
   242  
   243  }
   244  
   245  func TestImageWithMetadata(t *testing.T) {
   246  	assert := require.New(t)
   247  
   248  	image := fetchSunset(assert)
   249  
   250  	var meta = []map[string]interface{}{
   251  		{
   252  			"title": "My Sunset",
   253  			"name":  "Sunset #:counter",
   254  			"src":   "*.jpg",
   255  		},
   256  	}
   257  
   258  	assert.NoError(AssignMetadata(meta, image))
   259  	assert.Equal("Sunset #1", image.Name())
   260  
   261  	resized, err := image.Resize("200x")
   262  	assert.NoError(err)
   263  	assert.Equal("Sunset #1", resized.Name())
   264  
   265  }
   266  
   267  func TestImageResize8BitPNG(t *testing.T) {
   268  
   269  	assert := require.New(t)
   270  
   271  	image := fetchImage(assert, "gohugoio.png")
   272  
   273  	assert.Equal(imaging.PNG, image.format)
   274  	assert.Equal("/a/gohugoio.png", image.RelPermalink())
   275  	assert.Equal("image", image.ResourceType())
   276  
   277  	resized, err := image.Resize("800x")
   278  	assert.NoError(err)
   279  	assert.Equal(imaging.PNG, resized.format)
   280  	assert.Equal("/a/gohugoio_hu0e1b9e4a4be4d6f86c7b37b9ccce3fbc_73886_800x0_resize_linear_2.png", resized.RelPermalink())
   281  	assert.Equal(800, resized.Width())
   282  
   283  }
   284  
   285  func TestImageResizeInSubPath(t *testing.T) {
   286  
   287  	assert := require.New(t)
   288  
   289  	image := fetchImage(assert, "sub/gohugoio2.png")
   290  
   291  	assert.Equal(imaging.PNG, image.format)
   292  	assert.Equal("/a/sub/gohugoio2.png", image.RelPermalink())
   293  	assert.Equal("image", image.ResourceType())
   294  
   295  	resized, err := image.Resize("101x101")
   296  	assert.NoError(err)
   297  	assert.Equal(imaging.PNG, resized.format)
   298  	assert.Equal("/a/sub/gohugoio2_hu0e1b9e4a4be4d6f86c7b37b9ccce3fbc_73886_101x101_resize_linear_2.png", resized.RelPermalink())
   299  	assert.Equal(101, resized.Width())
   300  
   301  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, resized.RelPermalink(), 101, 101)
   302  	publishedImageFilename := filepath.Clean(resized.RelPermalink())
   303  	assertImageFile(assert, image.spec.BaseFs.PublishFs, publishedImageFilename, 101, 101)
   304  	assert.NoError(image.spec.BaseFs.PublishFs.Remove(publishedImageFilename))
   305  
   306  	// Cleare mem cache to simulate reading from the file cache.
   307  	resized.spec.imageCache.clear()
   308  
   309  	resizedAgain, err := image.Resize("101x101")
   310  	assert.NoError(err)
   311  	assert.Equal("/a/sub/gohugoio2_hu0e1b9e4a4be4d6f86c7b37b9ccce3fbc_73886_101x101_resize_linear_2.png", resizedAgain.RelPermalink())
   312  	assert.Equal(101, resizedAgain.Width())
   313  	assertFileCache(assert, image.spec.BaseFs.ResourcesFs, resizedAgain.RelPermalink(), 101, 101)
   314  	assertImageFile(assert, image.spec.BaseFs.PublishFs, publishedImageFilename, 101, 101)
   315  
   316  }
   317  
   318  func TestSVGImage(t *testing.T) {
   319  	assert := require.New(t)
   320  	spec := newTestResourceSpec(assert)
   321  	svg := fetchResourceForSpec(spec, assert, "circle.svg")
   322  	assert.NotNil(svg)
   323  }
   324  
   325  func TestSVGImageContent(t *testing.T) {
   326  	assert := require.New(t)
   327  	spec := newTestResourceSpec(assert)
   328  	svg := fetchResourceForSpec(spec, assert, "circle.svg")
   329  	assert.NotNil(svg)
   330  
   331  	content, err := svg.Content()
   332  	assert.NoError(err)
   333  	assert.IsType("", content)
   334  	assert.Contains(content.(string), `<svg height="100" width="100">`)
   335  }
   336  
   337  func BenchmarkResizeParallel(b *testing.B) {
   338  	assert := require.New(b)
   339  	img := fetchSunset(assert)
   340  
   341  	b.RunParallel(func(pb *testing.PB) {
   342  		for pb.Next() {
   343  			w := rand.Intn(10) + 10
   344  			resized, err := img.Resize(strconv.Itoa(w) + "x")
   345  			if err != nil {
   346  				b.Fatal(err)
   347  			}
   348  			_, err = resized.Resize(strconv.Itoa(w-1) + "x")
   349  			if err != nil {
   350  				b.Fatal(err)
   351  			}
   352  		}
   353  	})
   354  }