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