hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

resource_test.go (9853B)

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