github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/resources/page/permalinks_test.go (about)

     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 page
    15  
    16  import (
    17  	"fmt"
    18  	"regexp"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  
    23  	qt "github.com/frankban/quicktest"
    24  )
    25  
    26  // testdataPermalinks is used by a couple of tests; the expandsTo content is
    27  // subject to the data in simplePageJSON.
    28  var testdataPermalinks = []struct {
    29  	spec      string
    30  	valid     bool
    31  	expandsTo string
    32  }{
    33  	{":title", true, "spf13-vim-3.0-release-and-new-website"},
    34  	{"/:year-:month-:title", true, "/2012-04-spf13-vim-3.0-release-and-new-website"},
    35  	{"/:year/:yearday/:month/:monthname/:day/:weekday/:weekdayname/", true, "/2012/97/04/April/06/5/Friday/"}, // Dates
    36  	{"/:section/", true, "/blue/"},                                  // Section
    37  	{"/:title/", true, "/spf13-vim-3.0-release-and-new-website/"},   // Title
    38  	{"/:slug/", true, "/the-slug/"},                                 // Slug
    39  	{"/:slugorfilename/", true, "/the-slug/"},                       // Slug or filename
    40  	{"/:filename/", true, "/test-page/"},                            // Filename
    41  	{"/:06-:1-:2-:Monday", true, "/12-4-6-Friday"},                  // Dates with Go formatting
    42  	{"/:2006_01_02_15_04_05.000", true, "/2012_04_06_03_01_59.000"}, // Complicated custom date format
    43  	{"/:sections/", true, "/a/b/c/"},                                // Sections
    44  	{"/:sections[last]/", true, "/c/"},                              // Sections
    45  	{"/:sections[0]/:sections[last]/", true, "/a/c/"},               // Sections
    46  
    47  	// Failures
    48  	{"/blog/:fred", false, ""},
    49  	{"/:year//:title", false, ""},
    50  	{"/:TITLE", false, ""},      // case is not normalized
    51  	{"/:2017", false, ""},       // invalid date format
    52  	{"/:2006-01-02", false, ""}, // valid date format but invalid attribute name
    53  }
    54  
    55  func TestPermalinkExpansion(t *testing.T) {
    56  	t.Parallel()
    57  
    58  	c := qt.New(t)
    59  
    60  	page := newTestPageWithFile("/test-page/index.md")
    61  	page.title = "Spf13 Vim 3.0 Release and new website"
    62  	d, _ := time.Parse("2006-01-02 15:04:05", "2012-04-06 03:01:59")
    63  	page.date = d
    64  	page.section = "blue"
    65  	page.slug = "The Slug"
    66  
    67  	for _, item := range testdataPermalinks {
    68  		if !item.valid {
    69  			continue
    70  		}
    71  
    72  		specNameCleaner := regexp.MustCompile(`[\:\/\[\]]`)
    73  		name := specNameCleaner.ReplaceAllString(item.spec, "")
    74  
    75  		c.Run(name, func(c *qt.C) {
    76  
    77  			permalinksConfig := map[string]string{
    78  				"posts": item.spec,
    79  			}
    80  
    81  			ps := newTestPathSpec()
    82  			ps.Cfg.Set("permalinks", permalinksConfig)
    83  
    84  			expander, err := NewPermalinkExpander(ps)
    85  			c.Assert(err, qt.IsNil)
    86  
    87  			expanded, err := expander.Expand("posts", page)
    88  			c.Assert(err, qt.IsNil)
    89  			c.Assert(expanded, qt.Equals, item.expandsTo)
    90  		})
    91  
    92  	}
    93  }
    94  
    95  func TestPermalinkExpansionMultiSection(t *testing.T) {
    96  	t.Parallel()
    97  
    98  	c := qt.New(t)
    99  
   100  	page := newTestPage()
   101  	page.title = "Page Title"
   102  	d, _ := time.Parse("2006-01-02", "2012-04-06")
   103  	page.date = d
   104  	page.section = "blue"
   105  	page.slug = "The Slug"
   106  
   107  	page_slug_fallback := newTestPageWithFile("/page-filename/index.md")
   108  	page_slug_fallback.title = "Page Title"
   109  
   110  	permalinksConfig := map[string]string{
   111  		"posts":   "/:slug",
   112  		"blog":    "/:section/:year",
   113  		"recipes": "/:slugorfilename",
   114  	}
   115  
   116  	ps := newTestPathSpec()
   117  	ps.Cfg.Set("permalinks", permalinksConfig)
   118  
   119  	expander, err := NewPermalinkExpander(ps)
   120  	c.Assert(err, qt.IsNil)
   121  
   122  	expanded, err := expander.Expand("posts", page)
   123  	c.Assert(err, qt.IsNil)
   124  	c.Assert(expanded, qt.Equals, "/the-slug")
   125  
   126  	expanded, err = expander.Expand("blog", page)
   127  	c.Assert(err, qt.IsNil)
   128  	c.Assert(expanded, qt.Equals, "/blue/2012")
   129  
   130  	expanded, err = expander.Expand("posts", page_slug_fallback)
   131  	c.Assert(err, qt.IsNil)
   132  	c.Assert(expanded, qt.Equals, "/page-title")
   133  
   134  	expanded, err = expander.Expand("recipes", page_slug_fallback)
   135  	c.Assert(err, qt.IsNil)
   136  	c.Assert(expanded, qt.Equals, "/page-filename")
   137  }
   138  
   139  func TestPermalinkExpansionConcurrent(t *testing.T) {
   140  	t.Parallel()
   141  
   142  	c := qt.New(t)
   143  
   144  	permalinksConfig := map[string]string{
   145  		"posts": "/:slug/",
   146  	}
   147  
   148  	ps := newTestPathSpec()
   149  	ps.Cfg.Set("permalinks", permalinksConfig)
   150  
   151  	expander, err := NewPermalinkExpander(ps)
   152  	c.Assert(err, qt.IsNil)
   153  
   154  	var wg sync.WaitGroup
   155  
   156  	for i := 1; i < 20; i++ {
   157  		wg.Add(1)
   158  		go func(i int) {
   159  			defer wg.Done()
   160  			page := newTestPage()
   161  			for j := 1; j < 20; j++ {
   162  				page.slug = fmt.Sprintf("slug%d", i+j)
   163  				expanded, err := expander.Expand("posts", page)
   164  				c.Assert(err, qt.IsNil)
   165  				c.Assert(expanded, qt.Equals, fmt.Sprintf("/%s/", page.slug))
   166  			}
   167  		}(i)
   168  	}
   169  
   170  	wg.Wait()
   171  }
   172  
   173  func TestPermalinkExpansionSliceSyntax(t *testing.T) {
   174  	t.Parallel()
   175  
   176  	c := qt.New(t)
   177  	exp, _ := NewPermalinkExpander(newTestPathSpec())
   178  	slice := []string{"a", "b", "c", "d"}
   179  	fn := func(s string) []string {
   180  		return exp.toSliceFunc(s)(slice)
   181  	}
   182  
   183  	c.Run("Basic", func(c *qt.C) {
   184  		c.Assert(fn("[1:3]"), qt.DeepEquals, []string{"b", "c"})
   185  		c.Assert(fn("[1:]"), qt.DeepEquals, []string{"b", "c", "d"})
   186  		c.Assert(fn("[:2]"), qt.DeepEquals, []string{"a", "b"})
   187  		c.Assert(fn("[0:2]"), qt.DeepEquals, []string{"a", "b"})
   188  		c.Assert(fn("[:]"), qt.DeepEquals, []string{"a", "b", "c", "d"})
   189  		c.Assert(fn(""), qt.DeepEquals, []string{"a", "b", "c", "d"})
   190  		c.Assert(fn("[last]"), qt.DeepEquals, []string{"d"})
   191  		c.Assert(fn("[:last]"), qt.DeepEquals, []string{"a", "b", "c"})
   192  
   193  	})
   194  
   195  	c.Run("Out of bounds", func(c *qt.C) {
   196  		c.Assert(fn("[1:5]"), qt.DeepEquals, []string{"b", "c", "d"})
   197  		c.Assert(fn("[-1:5]"), qt.DeepEquals, []string{"a", "b", "c", "d"})
   198  		c.Assert(fn("[5:]"), qt.DeepEquals, []string{})
   199  		c.Assert(fn("[5:]"), qt.DeepEquals, []string{})
   200  		c.Assert(fn("[5:32]"), qt.DeepEquals, []string{})
   201  		c.Assert(exp.toSliceFunc("[:1]")(nil), qt.DeepEquals, []string(nil))
   202  		c.Assert(exp.toSliceFunc("[:1]")([]string{}), qt.DeepEquals, []string(nil))
   203  
   204  		// These all return nil
   205  		c.Assert(fn("[]"), qt.IsNil)
   206  		c.Assert(fn("[1:}"), qt.IsNil)
   207  		c.Assert(fn("foo"), qt.IsNil)
   208  
   209  	})
   210  
   211  }
   212  
   213  func BenchmarkPermalinkExpand(b *testing.B) {
   214  	page := newTestPage()
   215  	page.title = "Hugo Rocks"
   216  	d, _ := time.Parse("2006-01-02", "2019-02-28")
   217  	page.date = d
   218  
   219  	permalinksConfig := map[string]string{
   220  		"posts": "/:year-:month-:title",
   221  	}
   222  
   223  	ps := newTestPathSpec()
   224  	ps.Cfg.Set("permalinks", permalinksConfig)
   225  
   226  	expander, err := NewPermalinkExpander(ps)
   227  	if err != nil {
   228  		b.Fatal(err)
   229  	}
   230  
   231  	b.ResetTimer()
   232  	for i := 0; i < b.N; i++ {
   233  		s, err := expander.Expand("posts", page)
   234  		if err != nil {
   235  			b.Fatal(err)
   236  		}
   237  		if s != "/2019-02-hugo-rocks" {
   238  			b.Fatal(s)
   239  		}
   240  
   241  	}
   242  }