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