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 }