page_paths_test.go (11738B)
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 "path/filepath" 19 "strings" 20 "testing" 21 22 "github.com/gohugoio/hugo/media" 23 24 "github.com/gohugoio/hugo/output" 25 ) 26 27 func TestPageTargetPath(t *testing.T) { 28 pathSpec := newTestPathSpec() 29 30 noExtNoDelimMediaType := media.WithDelimiterAndSuffixes(media.TextType, "", "") 31 noExtNoDelimMediaType.Delimiter = "" 32 33 // Netlify style _redirects 34 noExtDelimFormat := output.Format{ 35 Name: "NER", 36 MediaType: noExtNoDelimMediaType, 37 BaseName: "_redirects", 38 } 39 40 for _, langPrefixPath := range []string{"", "no"} { 41 for _, langPrefixLink := range []string{"", "no"} { 42 for _, uglyURLs := range []bool{false, true} { 43 44 tests := []struct { 45 name string 46 d TargetPathDescriptor 47 expected TargetPaths 48 }{ 49 {"JSON home", TargetPathDescriptor{Kind: KindHome, Type: output.JSONFormat}, TargetPaths{TargetFilename: "/index.json", SubResourceBaseTarget: "", Link: "/index.json"}}, 50 {"AMP home", TargetPathDescriptor{Kind: KindHome, Type: output.AMPFormat}, TargetPaths{TargetFilename: "/amp/index.html", SubResourceBaseTarget: "/amp", Link: "/amp/"}}, 51 {"HTML home", TargetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: output.HTMLFormat}, TargetPaths{TargetFilename: "/index.html", SubResourceBaseTarget: "", Link: "/"}}, 52 {"Netlify redirects", TargetPathDescriptor{Kind: KindHome, BaseName: "_index", Type: noExtDelimFormat}, TargetPaths{TargetFilename: "/_redirects", SubResourceBaseTarget: "", Link: "/_redirects"}}, 53 {"HTML section list", TargetPathDescriptor{ 54 Kind: KindSection, 55 Sections: []string{"sect1"}, 56 BaseName: "_index", 57 Type: output.HTMLFormat, 58 }, TargetPaths{TargetFilename: "/sect1/index.html", SubResourceBaseTarget: "/sect1", Link: "/sect1/"}}, 59 {"HTML taxonomy term", TargetPathDescriptor{ 60 Kind: KindTerm, 61 Sections: []string{"tags", "hugo"}, 62 BaseName: "_index", 63 Type: output.HTMLFormat, 64 }, TargetPaths{TargetFilename: "/tags/hugo/index.html", SubResourceBaseTarget: "/tags/hugo", Link: "/tags/hugo/"}}, 65 {"HTML taxonomy", TargetPathDescriptor{ 66 Kind: KindTaxonomy, 67 Sections: []string{"tags"}, 68 BaseName: "_index", 69 Type: output.HTMLFormat, 70 }, TargetPaths{TargetFilename: "/tags/index.html", SubResourceBaseTarget: "/tags", Link: "/tags/"}}, 71 { 72 "HTML page", TargetPathDescriptor{ 73 Kind: KindPage, 74 Dir: "/a/b", 75 BaseName: "mypage", 76 Sections: []string{"a"}, 77 Type: output.HTMLFormat, 78 }, TargetPaths{TargetFilename: "/a/b/mypage/index.html", SubResourceBaseTarget: "/a/b/mypage", Link: "/a/b/mypage/"}, 79 }, 80 81 { 82 "HTML page with index as base", TargetPathDescriptor{ 83 Kind: KindPage, 84 Dir: "/a/b", 85 BaseName: "index", 86 Sections: []string{"a"}, 87 Type: output.HTMLFormat, 88 }, TargetPaths{TargetFilename: "/a/b/index.html", SubResourceBaseTarget: "/a/b", Link: "/a/b/"}, 89 }, 90 91 { 92 "HTML page with special chars", TargetPathDescriptor{ 93 Kind: KindPage, 94 Dir: "/a/b", 95 BaseName: "My Page!", 96 Type: output.HTMLFormat, 97 }, TargetPaths{TargetFilename: "/a/b/my-page/index.html", SubResourceBaseTarget: "/a/b/my-page", Link: "/a/b/my-page/"}, 98 }, 99 {"RSS home", TargetPathDescriptor{Kind: "rss", Type: output.RSSFormat}, TargetPaths{TargetFilename: "/index.xml", SubResourceBaseTarget: "", Link: "/index.xml"}}, 100 {"RSS section list", TargetPathDescriptor{ 101 Kind: "rss", 102 Sections: []string{"sect1"}, 103 Type: output.RSSFormat, 104 }, TargetPaths{TargetFilename: "/sect1/index.xml", SubResourceBaseTarget: "/sect1", Link: "/sect1/index.xml"}}, 105 { 106 "AMP page", TargetPathDescriptor{ 107 Kind: KindPage, 108 Dir: "/a/b/c", 109 BaseName: "myamp", 110 Type: output.AMPFormat, 111 }, TargetPaths{TargetFilename: "/amp/a/b/c/myamp/index.html", SubResourceBaseTarget: "/amp/a/b/c/myamp", Link: "/amp/a/b/c/myamp/"}, 112 }, 113 { 114 "AMP page with URL with suffix", TargetPathDescriptor{ 115 Kind: KindPage, 116 Dir: "/sect/", 117 BaseName: "mypage", 118 URL: "/some/other/url.xhtml", 119 Type: output.HTMLFormat, 120 }, TargetPaths{TargetFilename: "/some/other/url.xhtml", SubResourceBaseTarget: "/some/other", Link: "/some/other/url.xhtml"}, 121 }, 122 { 123 "JSON page with URL without suffix", TargetPathDescriptor{ 124 Kind: KindPage, 125 Dir: "/sect/", 126 BaseName: "mypage", 127 URL: "/some/other/path/", 128 Type: output.JSONFormat, 129 }, TargetPaths{TargetFilename: "/some/other/path/index.json", SubResourceBaseTarget: "/some/other/path", Link: "/some/other/path/index.json"}, 130 }, 131 { 132 "JSON page with URL without suffix and no trailing slash", TargetPathDescriptor{ 133 Kind: KindPage, 134 Dir: "/sect/", 135 BaseName: "mypage", 136 URL: "/some/other/path", 137 Type: output.JSONFormat, 138 }, TargetPaths{TargetFilename: "/some/other/path/index.json", SubResourceBaseTarget: "/some/other/path", Link: "/some/other/path/index.json"}, 139 }, 140 { 141 "HTML page with URL without suffix and no trailing slash", TargetPathDescriptor{ 142 Kind: KindPage, 143 Dir: "/sect/", 144 BaseName: "mypage", 145 URL: "/some/other/path", 146 Type: output.HTMLFormat, 147 }, TargetPaths{TargetFilename: "/some/other/path/index.html", SubResourceBaseTarget: "/some/other/path", Link: "/some/other/path/"}, 148 }, 149 { 150 "HTML page with URL containing double hyphen", TargetPathDescriptor{ 151 Kind: KindPage, 152 Dir: "/sect/", 153 BaseName: "mypage", 154 URL: "/some/other--url/", 155 Type: output.HTMLFormat, 156 }, TargetPaths{TargetFilename: "/some/other--url/index.html", SubResourceBaseTarget: "/some/other--url", Link: "/some/other--url/"}, 157 }, 158 { 159 "HTML page with expanded permalink", TargetPathDescriptor{ 160 Kind: KindPage, 161 Dir: "/a/b", 162 BaseName: "mypage", 163 ExpandedPermalink: "/2017/10/my-title/", 164 Type: output.HTMLFormat, 165 }, TargetPaths{TargetFilename: "/2017/10/my-title/index.html", SubResourceBaseTarget: "/2017/10/my-title", Link: "/2017/10/my-title/"}, 166 }, 167 { 168 "Paginated HTML home", TargetPathDescriptor{ 169 Kind: KindHome, 170 BaseName: "_index", 171 Type: output.HTMLFormat, 172 Addends: "page/3", 173 }, TargetPaths{TargetFilename: "/page/3/index.html", SubResourceBaseTarget: "/page/3", Link: "/page/3/"}, 174 }, 175 { 176 "Paginated Taxonomy terms list", TargetPathDescriptor{ 177 Kind: KindTerm, 178 BaseName: "_index", 179 Sections: []string{"tags", "hugo"}, 180 Type: output.HTMLFormat, 181 Addends: "page/3", 182 }, TargetPaths{TargetFilename: "/tags/hugo/page/3/index.html", SubResourceBaseTarget: "/tags/hugo/page/3", Link: "/tags/hugo/page/3/"}, 183 }, 184 { 185 "Regular page with addend", TargetPathDescriptor{ 186 Kind: KindPage, 187 Dir: "/a/b", 188 BaseName: "mypage", 189 Addends: "c/d/e", 190 Type: output.HTMLFormat, 191 }, TargetPaths{TargetFilename: "/a/b/mypage/c/d/e/index.html", SubResourceBaseTarget: "/a/b/mypage/c/d/e", Link: "/a/b/mypage/c/d/e/"}, 192 }, 193 } 194 195 for i, test := range tests { 196 t.Run(fmt.Sprintf("langPrefixPath=%s,langPrefixLink=%s,uglyURLs=%t,name=%s", langPrefixPath, langPrefixLink, uglyURLs, test.name), 197 func(t *testing.T) { 198 test.d.ForcePrefix = true 199 test.d.PathSpec = pathSpec 200 test.d.UglyURLs = uglyURLs 201 test.d.PrefixFilePath = langPrefixPath 202 test.d.PrefixLink = langPrefixLink 203 test.d.Dir = filepath.FromSlash(test.d.Dir) 204 isUgly := uglyURLs && !test.d.Type.NoUgly 205 206 expected := test.expected 207 208 // TODO(bep) simplify 209 if test.d.Kind == KindPage && test.d.BaseName == test.d.Type.BaseName { 210 } else if test.d.Kind == KindHome && test.d.Type.Path != "" { 211 } else if test.d.Type.MediaType.FirstSuffix.Suffix != "" && (!strings.HasPrefix(expected.TargetFilename, "/index") || test.d.Addends != "") && test.d.URL == "" && isUgly { 212 expected.TargetFilename = strings.Replace(expected.TargetFilename, 213 "/"+test.d.Type.BaseName+"."+test.d.Type.MediaType.FirstSuffix.Suffix, 214 "."+test.d.Type.MediaType.FirstSuffix.Suffix, 1) 215 expected.Link = strings.TrimSuffix(expected.Link, "/") + "." + test.d.Type.MediaType.FirstSuffix.Suffix 216 217 } 218 219 if test.d.PrefixFilePath != "" && !strings.HasPrefix(test.d.URL, "/"+test.d.PrefixFilePath) { 220 expected.TargetFilename = "/" + test.d.PrefixFilePath + expected.TargetFilename 221 expected.SubResourceBaseTarget = "/" + test.d.PrefixFilePath + expected.SubResourceBaseTarget 222 } 223 224 if test.d.PrefixLink != "" && !strings.HasPrefix(test.d.URL, "/"+test.d.PrefixLink) { 225 expected.Link = "/" + test.d.PrefixLink + expected.Link 226 } 227 228 expected.TargetFilename = filepath.FromSlash(expected.TargetFilename) 229 expected.SubResourceBaseTarget = filepath.FromSlash(expected.SubResourceBaseTarget) 230 231 pagePath := CreateTargetPaths(test.d) 232 233 if !eqTargetPaths(pagePath, expected) { 234 t.Fatalf("[%d] [%s] targetPath expected\n%#v, got:\n%#v", i, test.name, expected, pagePath) 235 } 236 }) 237 } 238 } 239 } 240 } 241 } 242 243 func TestPageTargetPathPrefix(t *testing.T) { 244 pathSpec := newTestPathSpec() 245 tests := []struct { 246 name string 247 d TargetPathDescriptor 248 expected TargetPaths 249 }{ 250 { 251 "URL set, prefix both, no force", 252 TargetPathDescriptor{Kind: KindPage, Type: output.JSONFormat, URL: "/mydir/my.json", ForcePrefix: false, PrefixFilePath: "pf", PrefixLink: "pl"}, 253 TargetPaths{TargetFilename: "/mydir/my.json", SubResourceBaseTarget: "/mydir", SubResourceBaseLink: "/mydir", Link: "/mydir/my.json"}, 254 }, 255 { 256 "URL set, prefix both, force", 257 TargetPathDescriptor{Kind: KindPage, Type: output.JSONFormat, URL: "/mydir/my.json", ForcePrefix: true, PrefixFilePath: "pf", PrefixLink: "pl"}, 258 TargetPaths{TargetFilename: "/pf/mydir/my.json", SubResourceBaseTarget: "/pf/mydir", SubResourceBaseLink: "/pl/mydir", Link: "/pl/mydir/my.json"}, 259 }, 260 } 261 262 for i, test := range tests { 263 t.Run(fmt.Sprintf(test.name), 264 func(t *testing.T) { 265 test.d.PathSpec = pathSpec 266 expected := test.expected 267 expected.TargetFilename = filepath.FromSlash(expected.TargetFilename) 268 expected.SubResourceBaseTarget = filepath.FromSlash(expected.SubResourceBaseTarget) 269 270 pagePath := CreateTargetPaths(test.d) 271 272 if pagePath != expected { 273 t.Fatalf("[%d] [%s] targetPath expected\n%#v, got:\n%#v", i, test.name, expected, pagePath) 274 } 275 }) 276 } 277 } 278 279 func eqTargetPaths(p1, p2 TargetPaths) bool { 280 if p1.Link != p2.Link { 281 return false 282 } 283 284 if p1.SubResourceBaseTarget != p2.SubResourceBaseTarget { 285 return false 286 } 287 288 if p1.TargetFilename != p2.TargetFilename { 289 return false 290 } 291 292 return true 293 }