github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/resource/resource_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  	"path"
    20  	"path/filepath"
    21  	"strings"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func TestGenericResource(t *testing.T) {
    29  	assert := require.New(t)
    30  	spec := newTestResourceSpec(assert)
    31  
    32  	r := spec.newGenericResource(nil, nil, "/a/foo.css", "foo.css", "css")
    33  
    34  	assert.Equal("https://example.com/foo.css", r.Permalink())
    35  	assert.Equal("/foo.css", r.RelPermalink())
    36  	assert.Equal("css", r.ResourceType())
    37  
    38  }
    39  
    40  func TestGenericResourceWithLinkFacory(t *testing.T) {
    41  	assert := require.New(t)
    42  	spec := newTestResourceSpec(assert)
    43  
    44  	factory := func(s string) string {
    45  		return path.Join("/foo", s)
    46  	}
    47  	r := spec.newGenericResource(factory, nil, "/a/foo.css", "foo.css", "css")
    48  
    49  	assert.Equal("https://example.com/foo/foo.css", r.Permalink())
    50  	assert.Equal("/foo/foo.css", r.RelPermalink())
    51  	assert.Equal("css", r.ResourceType())
    52  }
    53  
    54  func TestNewResourceFromFilename(t *testing.T) {
    55  	assert := require.New(t)
    56  	spec := newTestResourceSpec(assert)
    57  
    58  	writeSource(t, spec.Fs, "content/a/b/logo.png", "image")
    59  	writeSource(t, spec.Fs, "content/a/b/data.json", "json")
    60  
    61  	r, err := spec.NewResourceFromFilename(nil,
    62  		filepath.FromSlash("a/b/logo.png"), filepath.FromSlash("a/b/logo.png"))
    63  
    64  	assert.NoError(err)
    65  	assert.NotNil(r)
    66  	assert.Equal("image", r.ResourceType())
    67  	assert.Equal("/a/b/logo.png", r.RelPermalink())
    68  	assert.Equal("https://example.com/a/b/logo.png", r.Permalink())
    69  
    70  	r, err = spec.NewResourceFromFilename(nil, "a/b/data.json", "a/b/data.json")
    71  
    72  	assert.NoError(err)
    73  	assert.NotNil(r)
    74  	assert.Equal("json", r.ResourceType())
    75  
    76  	cloned := r.(Cloner).WithNewBase("aceof")
    77  	assert.Equal(r.ResourceType(), cloned.ResourceType())
    78  	assert.Equal("/aceof/a/b/data.json", cloned.RelPermalink())
    79  }
    80  
    81  func TestNewResourceFromFilenameSubPathInBaseURL(t *testing.T) {
    82  	assert := require.New(t)
    83  	spec := newTestResourceSpecForBaseURL(assert, "https://example.com/docs")
    84  
    85  	writeSource(t, spec.Fs, "content/a/b/logo.png", "image")
    86  
    87  	r, err := spec.NewResourceFromFilename(nil,
    88  		filepath.FromSlash("a/b/logo.png"), 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.target())
    97  
    98  }
    99  
   100  func TestResourcesByType(t *testing.T) {
   101  	assert := require.New(t)
   102  	spec := newTestResourceSpec(assert)
   103  	resources := Resources{
   104  		spec.newGenericResource(nil, nil, "/a/foo1.css", "foo1.css", "css"),
   105  		spec.newGenericResource(nil, nil, "/a/logo.png", "logo.css", "image"),
   106  		spec.newGenericResource(nil, nil, "/a/foo2.css", "foo2.css", "css"),
   107  		spec.newGenericResource(nil, nil, "/a/foo3.css", "foo3.css", "css")}
   108  
   109  	assert.Len(resources.ByType("css"), 3)
   110  	assert.Len(resources.ByType("image"), 1)
   111  
   112  }
   113  
   114  func TestResourcesGetByPrefix(t *testing.T) {
   115  	assert := require.New(t)
   116  	spec := newTestResourceSpec(assert)
   117  	resources := Resources{
   118  		spec.newGenericResource(nil, nil, "/a/foo1.css", "foo1.css", "css"),
   119  		spec.newGenericResource(nil, nil, "/a/logo1.png", "logo1.png", "image"),
   120  		spec.newGenericResource(nil, nil, "/b/Logo2.png", "Logo2.png", "image"),
   121  		spec.newGenericResource(nil, nil, "/b/foo2.css", "foo2.css", "css"),
   122  		spec.newGenericResource(nil, nil, "/b/foo3.css", "foo3.css", "css")}
   123  
   124  	assert.Nil(resources.GetByPrefix("asdf"))
   125  	assert.Equal("/logo1.png", resources.GetByPrefix("logo").RelPermalink())
   126  	assert.Equal("/logo1.png", resources.GetByPrefix("loGo").RelPermalink())
   127  	assert.Equal("/Logo2.png", resources.GetByPrefix("logo2").RelPermalink())
   128  	assert.Equal("/foo2.css", resources.GetByPrefix("foo2").RelPermalink())
   129  	assert.Equal("/foo1.css", resources.GetByPrefix("foo1").RelPermalink())
   130  	assert.Equal("/foo1.css", resources.GetByPrefix("foo1").RelPermalink())
   131  	assert.Nil(resources.GetByPrefix("asdfasdf"))
   132  
   133  	assert.Equal(2, len(resources.ByPrefix("logo")))
   134  	assert.Equal(1, len(resources.ByPrefix("logo2")))
   135  
   136  	logo := resources.GetByPrefix("logo")
   137  	assert.NotNil(logo.Params())
   138  	assert.Equal("logo1.png", logo.Name())
   139  	assert.Equal("logo1.png", logo.Title())
   140  
   141  }
   142  
   143  func TestResourcesGetMatch(t *testing.T) {
   144  	assert := require.New(t)
   145  	spec := newTestResourceSpec(assert)
   146  	resources := Resources{
   147  		spec.newGenericResource(nil, nil, "/a/foo1.css", "foo1.css", "css"),
   148  		spec.newGenericResource(nil, nil, "/a/logo1.png", "logo1.png", "image"),
   149  		spec.newGenericResource(nil, nil, "/b/Logo2.png", "Logo2.png", "image"),
   150  		spec.newGenericResource(nil, nil, "/b/foo2.css", "foo2.css", "css"),
   151  		spec.newGenericResource(nil, nil, "/b/foo3.css", "foo3.css", "css"),
   152  		spec.newGenericResource(nil, nil, "/b/c/foo4.css", "c/foo4.css", "css"),
   153  		spec.newGenericResource(nil, nil, "/b/c/foo5.css", "c/foo5.css", "css"),
   154  		spec.newGenericResource(nil, nil, "/b/c/d/foo6.css", "c/d/foo6.css", "css"),
   155  	}
   156  
   157  	assert.Equal("/logo1.png", resources.GetMatch("logo*").RelPermalink())
   158  	assert.Equal("/logo1.png", resources.GetMatch("loGo*").RelPermalink())
   159  	assert.Equal("/Logo2.png", resources.GetMatch("logo2*").RelPermalink())
   160  	assert.Equal("/foo2.css", resources.GetMatch("foo2*").RelPermalink())
   161  	assert.Equal("/foo1.css", resources.GetMatch("foo1*").RelPermalink())
   162  	assert.Equal("/foo1.css", resources.GetMatch("foo1*").RelPermalink())
   163  	assert.Equal("/c/foo4.css", resources.GetMatch("*/foo*").RelPermalink())
   164  
   165  	assert.Nil(resources.GetMatch("asdfasdf"))
   166  
   167  	assert.Equal(2, len(resources.Match("Logo*")))
   168  	assert.Equal(1, len(resources.Match("logo2*")))
   169  	assert.Equal(2, len(resources.Match("c/*")))
   170  
   171  	assert.Equal(6, len(resources.Match("**.css")))
   172  	assert.Equal(3, len(resources.Match("**/*.css")))
   173  	assert.Equal(1, len(resources.Match("c/**/*.css")))
   174  
   175  	// Matches only CSS files in c/
   176  	assert.Equal(3, len(resources.Match("c/**.css")))
   177  
   178  	// Matches all CSS files below c/ (including in c/d/)
   179  	assert.Equal(3, len(resources.Match("c/**.css")))
   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  	assert.Equal(0, len(resources.Match("/c/**.css")))
   186  
   187  }
   188  
   189  func TestAssignMetadata(t *testing.T) {
   190  	assert := require.New(t)
   191  	spec := newTestResourceSpec(assert)
   192  
   193  	var foo1, foo2, foo3, logo1, logo2, logo3 Resource
   194  	var resources Resources
   195  
   196  	for _, this := range []struct {
   197  		metaData   []map[string]interface{}
   198  		assertFunc func(err error)
   199  	}{
   200  		{[]map[string]interface{}{
   201  			{
   202  				"title": "My Resource",
   203  				"name":  "My Name",
   204  				"src":   "*",
   205  			},
   206  		}, func(err error) {
   207  			assert.Equal("My Resource", logo1.Title())
   208  			assert.Equal("My Name", logo1.Name())
   209  			assert.Equal("My Name", foo2.Name())
   210  
   211  		}},
   212  		{[]map[string]interface{}{
   213  			{
   214  				"title": "My Logo",
   215  				"src":   "*loGo*",
   216  			},
   217  			{
   218  				"title": "My Resource",
   219  				"name":  "My Name",
   220  				"src":   "*",
   221  			},
   222  		}, func(err error) {
   223  			assert.Equal("My Logo", logo1.Title())
   224  			assert.Equal("My Logo", logo2.Title())
   225  			assert.Equal("My Name", logo1.Name())
   226  			assert.Equal("My Name", foo2.Name())
   227  			assert.Equal("My Name", foo3.Name())
   228  			assert.Equal("My Resource", foo3.Title())
   229  
   230  		}},
   231  		{[]map[string]interface{}{
   232  			{
   233  				"title": "My Logo",
   234  				"src":   "*loGo*",
   235  				"params": map[string]interface{}{
   236  					"Param1": true,
   237  					"icon":   "logo",
   238  				},
   239  			},
   240  			{
   241  				"title": "My Resource",
   242  				"src":   "*",
   243  				"params": map[string]interface{}{
   244  					"Param2": true,
   245  					"icon":   "resource",
   246  				},
   247  			},
   248  		}, func(err error) {
   249  			assert.NoError(err)
   250  			assert.Equal("My Logo", logo1.Title())
   251  			assert.Equal("My Resource", foo3.Title())
   252  			_, p1 := logo2.Params()["param1"]
   253  			_, p2 := foo2.Params()["param2"]
   254  			_, p1_2 := foo2.Params()["param1"]
   255  			_, p2_2 := logo2.Params()["param2"]
   256  
   257  			icon1, _ := logo2.Params()["icon"]
   258  			icon2, _ := foo2.Params()["icon"]
   259  
   260  			assert.True(p1)
   261  			assert.True(p2)
   262  
   263  			// Check merge
   264  			assert.True(p2_2)
   265  			assert.False(p1_2)
   266  
   267  			assert.Equal("logo", icon1)
   268  			assert.Equal("resource", icon2)
   269  
   270  		}},
   271  		{[]map[string]interface{}{
   272  			{
   273  				"name": "Logo Name #:counter",
   274  				"src":  "*logo*",
   275  			},
   276  			{
   277  				"title": "Resource #:counter",
   278  				"name":  "Name #:counter",
   279  				"src":   "*",
   280  			},
   281  		}, func(err error) {
   282  			assert.NoError(err)
   283  			assert.Equal("Resource #2", logo2.Title())
   284  			assert.Equal("Logo Name #1", logo2.Name())
   285  			assert.Equal("Resource #4", logo1.Title())
   286  			assert.Equal("Logo Name #2", logo1.Name())
   287  			assert.Equal("Resource #1", foo2.Title())
   288  			assert.Equal("Resource #3", foo1.Title())
   289  			assert.Equal("Name #2", foo1.Name())
   290  			assert.Equal("Resource #5", foo3.Title())
   291  
   292  			assert.Equal(logo2, resources.GetByPrefix("logo name #1"))
   293  
   294  		}},
   295  		{[]map[string]interface{}{
   296  			{
   297  				"title": "Third Logo #:counter",
   298  				"src":   "logo3.png",
   299  			},
   300  			{
   301  				"title": "Other Logo #:counter",
   302  				"name":  "Name #:counter",
   303  				"src":   "logo*",
   304  			},
   305  		}, func(err error) {
   306  			assert.NoError(err)
   307  			assert.Equal("Third Logo #1", logo3.Title())
   308  			assert.Equal("Name #3", logo3.Name())
   309  			assert.Equal("Other Logo #1", logo2.Title())
   310  			assert.Equal("Name #1", logo2.Name())
   311  			assert.Equal("Other Logo #2", logo1.Title())
   312  			assert.Equal("Name #2", logo1.Name())
   313  
   314  		}},
   315  		{[]map[string]interface{}{
   316  			{
   317  				"title": "Third Logo",
   318  				"src":   "logo3.png",
   319  			},
   320  			{
   321  				"title": "Other Logo #:counter",
   322  				"name":  "Name #:counter",
   323  				"src":   "logo*",
   324  			},
   325  		}, func(err error) {
   326  			assert.NoError(err)
   327  			assert.Equal("Third Logo", logo3.Title())
   328  			assert.Equal("Name #3", logo3.Name())
   329  			assert.Equal("Other Logo #1", logo2.Title())
   330  			assert.Equal("Name #1", logo2.Name())
   331  			assert.Equal("Other Logo #2", logo1.Title())
   332  			assert.Equal("Name #2", logo1.Name())
   333  
   334  		}},
   335  		{[]map[string]interface{}{
   336  			{
   337  				"name": "third-logo",
   338  				"src":  "logo3.png",
   339  			},
   340  			{
   341  				"title": "Logo #:counter",
   342  				"name":  "Name #:counter",
   343  				"src":   "logo*",
   344  			},
   345  		}, func(err error) {
   346  			assert.NoError(err)
   347  			assert.Equal("Logo #3", logo3.Title())
   348  			assert.Equal("third-logo", logo3.Name())
   349  			assert.Equal("Logo #1", logo2.Title())
   350  			assert.Equal("Name #1", logo2.Name())
   351  			assert.Equal("Logo #2", logo1.Title())
   352  			assert.Equal("Name #2", logo1.Name())
   353  
   354  		}},
   355  		{[]map[string]interface{}{
   356  			{
   357  				"title": "Third Logo #:counter",
   358  			},
   359  		}, func(err error) {
   360  			// Missing src
   361  			assert.Error(err)
   362  
   363  		}},
   364  		{[]map[string]interface{}{
   365  			{
   366  				"title": "Title",
   367  				"src":   "[]",
   368  			},
   369  		}, func(err error) {
   370  			// Invalid pattern
   371  			assert.Error(err)
   372  
   373  		}},
   374  	} {
   375  
   376  		foo2 = spec.newGenericResource(nil, nil, "/b/foo2.css", "foo2.css", "css")
   377  		logo2 = spec.newGenericResource(nil, nil, "/b/Logo2.png", "Logo2.png", "image")
   378  		foo1 = spec.newGenericResource(nil, nil, "/a/foo1.css", "foo1.css", "css")
   379  		logo1 = spec.newGenericResource(nil, nil, "/a/logo1.png", "logo1.png", "image")
   380  		foo3 = spec.newGenericResource(nil, nil, "/b/foo3.css", "foo3.css", "css")
   381  		logo3 = spec.newGenericResource(nil, nil, "/b/logo3.png", "logo3.png", "image")
   382  
   383  		resources = Resources{
   384  			foo2,
   385  			logo2,
   386  			foo1,
   387  			logo1,
   388  			foo3,
   389  			logo3,
   390  		}
   391  
   392  		this.assertFunc(AssignMetadata(this.metaData, resources...))
   393  	}
   394  
   395  }
   396  
   397  func BenchmarkResourcesByPrefix(b *testing.B) {
   398  	resources := benchResources(b)
   399  	prefixes := []string{"abc", "jkl", "nomatch", "sub/"}
   400  	rnd := rand.New(rand.NewSource(time.Now().Unix()))
   401  
   402  	b.RunParallel(func(pb *testing.PB) {
   403  		for pb.Next() {
   404  			resources.ByPrefix(prefixes[rnd.Intn(len(prefixes))])
   405  		}
   406  	})
   407  }
   408  
   409  func BenchmarkResourcesMatch(b *testing.B) {
   410  	resources := benchResources(b)
   411  	prefixes := []string{"abc*", "jkl*", "nomatch*", "sub/*"}
   412  	rnd := rand.New(rand.NewSource(time.Now().Unix()))
   413  
   414  	b.RunParallel(func(pb *testing.PB) {
   415  		for pb.Next() {
   416  			resources.Match(prefixes[rnd.Intn(len(prefixes))])
   417  		}
   418  	})
   419  }
   420  
   421  // This adds a benchmark for the a100 test case as described by Russ Cox here:
   422  // https://research.swtch.com/glob (really interesting article)
   423  // I don't expect Hugo users to "stumble upon" this problem, so this is more to satisfy
   424  // my own curiosity.
   425  func BenchmarkResourcesMatchA100(b *testing.B) {
   426  	assert := require.New(b)
   427  	spec := newTestResourceSpec(assert)
   428  	a100 := strings.Repeat("a", 100)
   429  	pattern := "a*a*a*a*a*a*a*a*b"
   430  
   431  	resources := Resources{spec.newGenericResource(nil, nil, "/a/"+a100, a100, "css")}
   432  
   433  	b.ResetTimer()
   434  	for i := 0; i < b.N; i++ {
   435  		resources.Match(pattern)
   436  	}
   437  
   438  }
   439  
   440  func benchResources(b *testing.B) Resources {
   441  	assert := require.New(b)
   442  	spec := newTestResourceSpec(assert)
   443  	var resources Resources
   444  
   445  	for i := 0; i < 30; i++ {
   446  		name := fmt.Sprintf("abcde%d_%d.css", i%5, i)
   447  		resources = append(resources, spec.newGenericResource(nil, nil, "/a/"+name, name, "css"))
   448  	}
   449  
   450  	for i := 0; i < 30; i++ {
   451  		name := fmt.Sprintf("efghi%d_%d.css", i%5, i)
   452  		resources = append(resources, spec.newGenericResource(nil, nil, "/a/"+name, name, "css"))
   453  	}
   454  
   455  	for i := 0; i < 30; i++ {
   456  		name := fmt.Sprintf("jklmn%d_%d.css", i%5, i)
   457  		resources = append(resources, spec.newGenericResource(nil, nil, "/b/sub/"+name, "sub/"+name, "css"))
   458  	}
   459  
   460  	return resources
   461  
   462  }
   463  
   464  func BenchmarkAssignMetadata(b *testing.B) {
   465  	assert := require.New(b)
   466  	spec := newTestResourceSpec(assert)
   467  
   468  	for i := 0; i < b.N; i++ {
   469  		b.StopTimer()
   470  		var resources Resources
   471  		var meta = []map[string]interface{}{
   472  			{
   473  				"title": "Foo #:counter",
   474  				"name":  "Foo Name #:counter",
   475  				"src":   "foo1*",
   476  			},
   477  			{
   478  				"title": "Rest #:counter",
   479  				"name":  "Rest Name #:counter",
   480  				"src":   "*",
   481  			},
   482  		}
   483  		for i := 0; i < 20; i++ {
   484  			name := fmt.Sprintf("foo%d_%d.css", i%5, i)
   485  			resources = append(resources, spec.newGenericResource(nil, nil, "/a/"+name, name, "css"))
   486  		}
   487  		b.StartTimer()
   488  
   489  		if err := AssignMetadata(meta, resources...); err != nil {
   490  			b.Fatal(err)
   491  		}
   492  
   493  	}
   494  }