github.com/fighterlyt/hugo@v0.47.1/resource/resource_test.go (about) 1 // Copyright 2018 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 "path" 20 "path/filepath" 21 "strings" 22 "testing" 23 "time" 24 25 "github.com/gohugoio/hugo/media" 26 27 "github.com/stretchr/testify/require" 28 ) 29 30 func TestGenericResource(t *testing.T) { 31 assert := require.New(t) 32 spec := newTestResourceSpec(assert) 33 34 r := spec.newGenericResource(nil, nil, nil, "/a/foo.css", "foo.css", media.CSSType) 35 36 assert.Equal("https://example.com/foo.css", r.Permalink()) 37 assert.Equal("/foo.css", r.RelPermalink()) 38 assert.Equal("css", r.ResourceType()) 39 40 } 41 42 func TestGenericResourceWithLinkFacory(t *testing.T) { 43 assert := require.New(t) 44 spec := newTestResourceSpec(assert) 45 46 factory := func(s string) string { 47 return path.Join("/foo", s) 48 } 49 r := spec.newGenericResource(nil, factory, nil, "/a/foo.css", "foo.css", media.CSSType) 50 51 assert.Equal("https://example.com/foo/foo.css", r.Permalink()) 52 assert.Equal("/foo/foo.css", r.RelPermalink()) 53 assert.Equal("css", r.ResourceType()) 54 } 55 56 func TestNewResourceFromFilename(t *testing.T) { 57 assert := require.New(t) 58 spec := newTestResourceSpec(assert) 59 60 writeSource(t, spec.Fs, "content/a/b/logo.png", "image") 61 writeSource(t, spec.Fs, "content/a/b/data.json", "json") 62 63 r, err := spec.New(ResourceSourceDescriptor{SourceFilename: "a/b/logo.png"}) 64 65 assert.NoError(err) 66 assert.NotNil(r) 67 assert.Equal("image", r.ResourceType()) 68 assert.Equal("/a/b/logo.png", r.RelPermalink()) 69 assert.Equal("https://example.com/a/b/logo.png", r.Permalink()) 70 71 r, err = spec.New(ResourceSourceDescriptor{SourceFilename: "a/b/data.json"}) 72 73 assert.NoError(err) 74 assert.NotNil(r) 75 assert.Equal("json", r.ResourceType()) 76 77 cloned := r.(Cloner).WithNewBase("aceof") 78 assert.Equal(r.ResourceType(), cloned.ResourceType()) 79 assert.Equal("/aceof/a/b/data.json", cloned.RelPermalink()) 80 } 81 82 func TestNewResourceFromFilenameSubPathInBaseURL(t *testing.T) { 83 assert := require.New(t) 84 spec := newTestResourceSpecForBaseURL(assert, "https://example.com/docs") 85 86 writeSource(t, spec.Fs, "content/a/b/logo.png", "image") 87 88 r, err := spec.New(ResourceSourceDescriptor{SourceFilename: filepath.FromSlash("a/b/logo.png")}) 89 90 assert.NoError(err) 91 assert.NotNil(r) 92 assert.Equal("image", r.ResourceType()) 93 assert.Equal("/docs/a/b/logo.png", r.RelPermalink()) 94 assert.Equal("https://example.com/docs/a/b/logo.png", r.Permalink()) 95 img := r.(*Image) 96 assert.Equal(filepath.FromSlash("/a/b/logo.png"), img.targetFilenames()[0]) 97 98 } 99 100 var pngType, _ = media.FromStringAndExt("image/png", "png") 101 102 func TestResourcesByType(t *testing.T) { 103 assert := require.New(t) 104 spec := newTestResourceSpec(assert) 105 resources := Resources{ 106 spec.newGenericResource(nil, nil, nil, "/a/foo1.css", "foo1.css", media.CSSType), 107 spec.newGenericResource(nil, nil, nil, "/a/logo.png", "logo.css", pngType), 108 spec.newGenericResource(nil, nil, nil, "/a/foo2.css", "foo2.css", media.CSSType), 109 spec.newGenericResource(nil, nil, nil, "/a/foo3.css", "foo3.css", media.CSSType)} 110 111 assert.Len(resources.ByType("css"), 3) 112 assert.Len(resources.ByType("image"), 1) 113 114 } 115 116 func TestResourcesGetByPrefix(t *testing.T) { 117 assert := require.New(t) 118 spec := newTestResourceSpec(assert) 119 resources := Resources{ 120 spec.newGenericResource(nil, nil, nil, "/a/foo1.css", "foo1.css", media.CSSType), 121 spec.newGenericResource(nil, nil, nil, "/a/logo1.png", "logo1.png", pngType), 122 spec.newGenericResource(nil, nil, nil, "/b/Logo2.png", "Logo2.png", pngType), 123 spec.newGenericResource(nil, nil, nil, "/b/foo2.css", "foo2.css", media.CSSType), 124 spec.newGenericResource(nil, nil, nil, "/b/foo3.css", "foo3.css", media.CSSType)} 125 126 assert.Nil(resources.GetMatch("asdf*")) 127 assert.Equal("/logo1.png", resources.GetMatch("logo*").RelPermalink()) 128 assert.Equal("/logo1.png", resources.GetMatch("loGo*").RelPermalink()) 129 assert.Equal("/Logo2.png", resources.GetMatch("logo2*").RelPermalink()) 130 assert.Equal("/foo2.css", resources.GetMatch("foo2*").RelPermalink()) 131 assert.Equal("/foo1.css", resources.GetMatch("foo1*").RelPermalink()) 132 assert.Equal("/foo1.css", resources.GetMatch("foo1*").RelPermalink()) 133 assert.Nil(resources.GetMatch("asdfasdf*")) 134 135 assert.Equal(2, len(resources.Match("logo*"))) 136 assert.Equal(1, len(resources.Match("logo2*"))) 137 138 logo := resources.GetMatch("logo*") 139 assert.NotNil(logo.Params()) 140 assert.Equal("logo1.png", logo.Name()) 141 assert.Equal("logo1.png", logo.Title()) 142 143 } 144 145 func TestResourcesGetMatch(t *testing.T) { 146 assert := require.New(t) 147 spec := newTestResourceSpec(assert) 148 resources := Resources{ 149 spec.newGenericResource(nil, nil, nil, "/a/foo1.css", "foo1.css", media.CSSType), 150 spec.newGenericResource(nil, nil, nil, "/a/logo1.png", "logo1.png", pngType), 151 spec.newGenericResource(nil, nil, nil, "/b/Logo2.png", "Logo2.png", pngType), 152 spec.newGenericResource(nil, nil, nil, "/b/foo2.css", "foo2.css", media.CSSType), 153 spec.newGenericResource(nil, nil, nil, "/b/foo3.css", "foo3.css", media.CSSType), 154 spec.newGenericResource(nil, nil, nil, "/b/c/foo4.css", "c/foo4.css", media.CSSType), 155 spec.newGenericResource(nil, nil, nil, "/b/c/foo5.css", "c/foo5.css", media.CSSType), 156 spec.newGenericResource(nil, nil, nil, "/b/c/d/foo6.css", "c/d/foo6.css", media.CSSType), 157 } 158 159 assert.Equal("/logo1.png", resources.GetMatch("logo*").RelPermalink()) 160 assert.Equal("/logo1.png", resources.GetMatch("loGo*").RelPermalink()) 161 assert.Equal("/Logo2.png", resources.GetMatch("logo2*").RelPermalink()) 162 assert.Equal("/foo2.css", resources.GetMatch("foo2*").RelPermalink()) 163 assert.Equal("/foo1.css", resources.GetMatch("foo1*").RelPermalink()) 164 assert.Equal("/foo1.css", resources.GetMatch("foo1*").RelPermalink()) 165 assert.Equal("/c/foo4.css", resources.GetMatch("*/foo*").RelPermalink()) 166 167 assert.Nil(resources.GetMatch("asdfasdf")) 168 169 assert.Equal(2, len(resources.Match("Logo*"))) 170 assert.Equal(1, len(resources.Match("logo2*"))) 171 assert.Equal(2, len(resources.Match("c/*"))) 172 173 assert.Equal(6, len(resources.Match("**.css"))) 174 assert.Equal(3, len(resources.Match("**/*.css"))) 175 assert.Equal(1, len(resources.Match("c/**/*.css"))) 176 177 // Matches only CSS files in c/ 178 assert.Equal(3, len(resources.Match("c/**.css"))) 179 180 // Matches all CSS files below c/ (including in c/d/) 181 assert.Equal(3, len(resources.Match("c/**.css"))) 182 183 // Patterns beginning with a slash will not match anything. 184 // We could maybe consider trimming that slash, but let's be explicit about this. 185 // (it is possible for users to do a rename) 186 // This is analogous to standing in a directory and doing "ls *.*". 187 assert.Equal(0, len(resources.Match("/c/**.css"))) 188 189 } 190 191 func BenchmarkResourcesMatch(b *testing.B) { 192 resources := benchResources(b) 193 prefixes := []string{"abc*", "jkl*", "nomatch*", "sub/*"} 194 rnd := rand.New(rand.NewSource(time.Now().Unix())) 195 196 b.RunParallel(func(pb *testing.PB) { 197 for pb.Next() { 198 resources.Match(prefixes[rnd.Intn(len(prefixes))]) 199 } 200 }) 201 } 202 203 // This adds a benchmark for the a100 test case as described by Russ Cox here: 204 // https://research.swtch.com/glob (really interesting article) 205 // I don't expect Hugo users to "stumble upon" this problem, so this is more to satisfy 206 // my own curiosity. 207 func BenchmarkResourcesMatchA100(b *testing.B) { 208 assert := require.New(b) 209 spec := newTestResourceSpec(assert) 210 a100 := strings.Repeat("a", 100) 211 pattern := "a*a*a*a*a*a*a*a*b" 212 213 resources := Resources{spec.newGenericResource(nil, nil, nil, "/a/"+a100, a100, media.CSSType)} 214 215 b.ResetTimer() 216 for i := 0; i < b.N; i++ { 217 resources.Match(pattern) 218 } 219 220 } 221 222 func benchResources(b *testing.B) Resources { 223 assert := require.New(b) 224 spec := newTestResourceSpec(assert) 225 var resources Resources 226 227 for i := 0; i < 30; i++ { 228 name := fmt.Sprintf("abcde%d_%d.css", i%5, i) 229 resources = append(resources, spec.newGenericResource(nil, nil, nil, "/a/"+name, name, media.CSSType)) 230 } 231 232 for i := 0; i < 30; i++ { 233 name := fmt.Sprintf("efghi%d_%d.css", i%5, i) 234 resources = append(resources, spec.newGenericResource(nil, nil, nil, "/a/"+name, name, media.CSSType)) 235 } 236 237 for i := 0; i < 30; i++ { 238 name := fmt.Sprintf("jklmn%d_%d.css", i%5, i) 239 resources = append(resources, spec.newGenericResource(nil, nil, nil, "/b/sub/"+name, "sub/"+name, media.CSSType)) 240 } 241 242 return resources 243 244 } 245 246 func BenchmarkAssignMetadata(b *testing.B) { 247 assert := require.New(b) 248 spec := newTestResourceSpec(assert) 249 250 for i := 0; i < b.N; i++ { 251 b.StopTimer() 252 var resources Resources 253 var meta = []map[string]interface{}{ 254 { 255 "title": "Foo #:counter", 256 "name": "Foo Name #:counter", 257 "src": "foo1*", 258 }, 259 { 260 "title": "Rest #:counter", 261 "name": "Rest Name #:counter", 262 "src": "*", 263 }, 264 } 265 for i := 0; i < 20; i++ { 266 name := fmt.Sprintf("foo%d_%d.css", i%5, i) 267 resources = append(resources, spec.newGenericResource(nil, nil, nil, "/a/"+name, name, media.CSSType)) 268 } 269 b.StartTimer() 270 271 if err := AssignMetadata(meta, resources...); err != nil { 272 b.Fatal(err) 273 } 274 275 } 276 }