site_sections_test.go - hugo - [fork] hugo port for 9front
(HTM) git clone https://git.drkhsh.at/hugo.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
site_sections_test.go (15475B)
---
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 hugolib
15
16 import (
17 "fmt"
18 "path/filepath"
19 "strings"
20 "testing"
21
22 qt "github.com/frankban/quicktest"
23 "github.com/gohugoio/hugo/deps"
24 "github.com/gohugoio/hugo/htesting"
25 "github.com/gohugoio/hugo/resources/kinds"
26 "github.com/gohugoio/hugo/resources/page"
27 )
28
29 func TestNestedSections(t *testing.T) {
30 var (
31 c = qt.New(t)
32 cfg, fs = newTestCfg()
33 )
34
35 tt := htesting.NewPinnedRunner(c, "")
36
37 cfg.Set("permalinks", map[string]string{
38 "perm-a": ":sections/:title",
39 })
40
41 pageTemplate := `---
42 title: T%d_%d
43 ---
44 Content
45 `
46
47 // Home page
48 writeSource(t, fs, filepath.Join("content", "_index.md"), fmt.Sprintf(pageTemplate, -1, -1))
49
50 // Top level content page
51 writeSource(t, fs, filepath.Join("content", "mypage.md"), fmt.Sprintf(pageTemplate, 1234, 5))
52
53 // Top level section without index content page
54 writeSource(t, fs, filepath.Join("content", "top", "mypage2.md"), fmt.Sprintf(pageTemplate, 12345, 6))
55 // Just a page in a subfolder, i.e. not a section.
56 writeSource(t, fs, filepath.Join("content", "top", "folder", "mypage3.md"), fmt.Sprintf(pageTemplate, 12345, 67))
57
58 for level1 := 1; level1 < 3; level1++ {
59 writeSource(t, fs, filepath.Join("content", "l1", fmt.Sprintf("page_1_%d.md", level1)),
60 fmt.Sprintf(pageTemplate, 1, level1))
61 }
62
63 // Issue #3586
64 writeSource(t, fs, filepath.Join("content", "post", "0000.md"), fmt.Sprintf(pageTemplate, 1, 2))
65 writeSource(t, fs, filepath.Join("content", "post", "0000", "0001.md"), fmt.Sprintf(pageTemplate, 1, 3))
66 writeSource(t, fs, filepath.Join("content", "elsewhere", "0003.md"), fmt.Sprintf(pageTemplate, 1, 4))
67
68 // Empty nested section, i.e. no regular content pages.
69 writeSource(t, fs, filepath.Join("content", "empty1", "b", "c", "_index.md"), fmt.Sprintf(pageTemplate, 33, -1))
70 // Index content file a the end and in the middle.
71 writeSource(t, fs, filepath.Join("content", "empty2", "b", "_index.md"), fmt.Sprintf(pageTemplate, 40, -1))
72 writeSource(t, fs, filepath.Join("content", "empty2", "b", "c", "d", "_index.md"), fmt.Sprintf(pageTemplate, 41, -1))
73
74 // Empty with content file in the middle.
75 writeSource(t, fs, filepath.Join("content", "empty3", "b", "c", "d", "_index.md"), fmt.Sprintf(pageTemplate, 41, -1))
76 writeSource(t, fs, filepath.Join("content", "empty3", "b", "empty3.md"), fmt.Sprintf(pageTemplate, 3, -1))
77
78 // Section with permalink config
79 writeSource(t, fs, filepath.Join("content", "perm a", "link", "_index.md"), fmt.Sprintf(pageTemplate, 9, -1))
80 for i := 1; i < 4; i++ {
81 writeSource(t, fs, filepath.Join("content", "perm a", "link", fmt.Sprintf("page_%d.md", i)),
82 fmt.Sprintf(pageTemplate, 1, i))
83 }
84 writeSource(t, fs, filepath.Join("content", "perm a", "link", "regular", fmt.Sprintf("page_%d.md", 5)),
85 fmt.Sprintf(pageTemplate, 1, 5))
86
87 writeSource(t, fs, filepath.Join("content", "l1", "l2", "_index.md"), fmt.Sprintf(pageTemplate, 2, -1))
88 writeSource(t, fs, filepath.Join("content", "l1", "l2_2", "_index.md"), fmt.Sprintf(pageTemplate, 22, -1))
89 writeSource(t, fs, filepath.Join("content", "l1", "l2", "l3", "_index.md"), fmt.Sprintf(pageTemplate, 3, -1))
90
91 for level2 := 1; level2 < 4; level2++ {
92 writeSource(t, fs, filepath.Join("content", "l1", "l2", fmt.Sprintf("page_2_%d.md", level2)),
93 fmt.Sprintf(pageTemplate, 2, level2))
94 }
95 for level2 := 1; level2 < 3; level2++ {
96 writeSource(t, fs, filepath.Join("content", "l1", "l2_2", fmt.Sprintf("page_2_2_%d.md", level2)),
97 fmt.Sprintf(pageTemplate, 2, level2))
98 }
99 for level3 := 1; level3 < 3; level3++ {
100 writeSource(t, fs, filepath.Join("content", "l1", "l2", "l3", fmt.Sprintf("page_3_%d.md", level3)),
101 fmt.Sprintf(pageTemplate, 3, level3))
102 }
103
104 writeSource(t, fs, filepath.Join("content", "Spaces in Section", "page100.md"), fmt.Sprintf(pageTemplate, 10, 0))
105
106 writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), "<html>Single|{{ .Title }}</html>")
107 writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"),
108 `
109 {{ $sect := (.Site.GetPage "l1/l2") }}
110 <html>List|{{ .Title }}|L1/l2-IsActive: {{ .InSection $sect }}
111 {{ range .Paginator.Pages }}
112 PAG|{{ .Title }}|{{ $sect.InSection . }}
113 {{ end }}
114 {{/* https://github.com/gohugoio/hugo/issues/4989 */}}
115 {{ $sections := (.Site.GetPage "section" .Section).Sections.ByWeight }}
116 </html>`)
117
118 cfg.Set("pagination.pagerSize", 2)
119
120 th, configs := newTestHelperFromProvider(cfg, fs, t)
121
122 s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Configs: configs}, BuildCfg{})
123
124 c.Assert(len(s.RegularPages()), qt.Equals, 21)
125
126 tests := []struct {
127 sections string
128 verify func(c *qt.C, p page.Page)
129 }{
130 {"elsewhere", func(c *qt.C, p page.Page) {
131 c.Assert(len(p.Pages()), qt.Equals, 1)
132 for _, p := range p.Pages() {
133 c.Assert(p.SectionsPath(), qt.Equals, "/elsewhere")
134 }
135 }},
136 {"post", func(c *qt.C, p page.Page) {
137 c.Assert(len(p.Pages()), qt.Equals, 2)
138 for _, p := range p.Pages() {
139 c.Assert(p.Section(), qt.Equals, "post")
140 }
141 }},
142 {"empty1", func(c *qt.C, p page.Page) {
143 // > b,c
144 c.Assert(getPage(p, "/empty1/b"), qt.IsNil) // No _index.md page.
145 c.Assert(getPage(p, "/empty1/b/c"), qt.Not(qt.IsNil))
146 }},
147 {"empty2", func(c *qt.C, p page.Page) {
148 // > b,c,d where b and d have _index.md files.
149 b := getPage(p, "/empty2/b")
150 c.Assert(b, qt.Not(qt.IsNil))
151 c.Assert(b.Title(), qt.Equals, "T40_-1")
152
153 cp := getPage(p, "/empty2/b/c")
154 c.Assert(cp, qt.IsNil) // No _index.md
155
156 d := getPage(p, "/empty2/b/c/d")
157 c.Assert(d, qt.Not(qt.IsNil))
158 c.Assert(d.Title(), qt.Equals, "T41_-1")
159
160 c.Assert(cp.Eq(d), qt.Equals, false)
161 c.Assert(cp.Eq(cp), qt.Equals, true)
162 c.Assert(cp.Eq("asdf"), qt.Equals, false)
163 }},
164 {"empty3", func(c *qt.C, p page.Page) {
165 // b,c,d with regular page in b
166 b := getPage(p, "/empty3/b")
167 c.Assert(b, qt.IsNil) // No _index.md
168 e3 := getPage(p, "/empty3/b/empty3")
169 c.Assert(e3, qt.Not(qt.IsNil))
170 c.Assert(e3.File().LogicalName(), qt.Equals, "empty3.md")
171 }},
172 {"empty3", func(c *qt.C, p page.Page) {
173 xxx := getPage(p, "/empty3/nil")
174 c.Assert(xxx, qt.IsNil)
175 }},
176 {"top", func(c *qt.C, p page.Page) {
177 c.Assert(p.Title(), qt.Equals, "Tops")
178 c.Assert(len(p.Pages()), qt.Equals, 2)
179 c.Assert(p.Pages()[0].File().LogicalName(), qt.Equals, "mypage2.md")
180 c.Assert(p.Pages()[1].File().LogicalName(), qt.Equals, "mypage3.md")
181 home := p.Parent()
182 c.Assert(home.IsHome(), qt.Equals, true)
183 c.Assert(len(p.Sections()), qt.Equals, 0)
184 c.Assert(home.CurrentSection(), qt.Equals, home)
185 active := home.InSection(home)
186 c.Assert(active, qt.Equals, true)
187 c.Assert(p.FirstSection(), qt.Equals, p)
188 c.Assert(len(p.Ancestors()), qt.Equals, 1)
189 }},
190 {"l1", func(c *qt.C, p page.Page) {
191 c.Assert(p.Title(), qt.Equals, "L1s")
192 c.Assert(len(p.Pages()), qt.Equals, 4) // 2 pages + 2 sections
193 c.Assert(p.Parent().IsHome(), qt.Equals, true)
194 c.Assert(len(p.Sections()), qt.Equals, 2)
195 c.Assert(len(p.Ancestors()), qt.Equals, 1)
196 }},
197 {"l1,l2", func(c *qt.C, p page.Page) {
198 c.Assert(p.Title(), qt.Equals, "T2_-1")
199 c.Assert(len(p.Pages()), qt.Equals, 4) // 3 pages + 1 section
200 c.Assert(p.Pages()[0].Parent(), qt.Equals, p)
201 c.Assert(p.Parent().Title(), qt.Equals, "L1s")
202 c.Assert(p.RelPermalink(), qt.Equals, "/l1/l2/")
203 c.Assert(len(p.Sections()), qt.Equals, 1)
204 c.Assert(len(p.Ancestors()), qt.Equals, 2)
205
206 for _, child := range p.Pages() {
207 if child.IsSection() {
208 c.Assert(child.CurrentSection(), qt.Equals, child)
209 continue
210 }
211
212 c.Assert(child.CurrentSection(), qt.Equals, p)
213 active := child.InSection(p)
214
215 c.Assert(active, qt.Equals, true)
216 active = p.InSection(child)
217 c.Assert(active, qt.Equals, true)
218 active = p.InSection(getPage(p, "/"))
219 c.Assert(active, qt.Equals, false)
220
221 isAncestor := p.IsAncestor(child)
222 c.Assert(isAncestor, qt.Equals, true)
223 isAncestor = child.IsAncestor(p)
224 c.Assert(isAncestor, qt.Equals, false)
225
226 isDescendant := p.IsDescendant(child)
227 c.Assert(isDescendant, qt.Equals, false)
228 isDescendant = child.IsDescendant(p)
229 c.Assert(isDescendant, qt.Equals, true)
230 }
231
232 c.Assert(p.Eq(p.CurrentSection()), qt.Equals, true)
233 }},
234 {"l1,l2_2", func(c *qt.C, p page.Page) {
235 c.Assert(p.Title(), qt.Equals, "T22_-1")
236 c.Assert(len(p.Pages()), qt.Equals, 2)
237 c.Assert(p.Pages()[0].File().Path(), qt.Equals, filepath.FromSlash("l1/l2_2/page_2_2_1.md"))
238 c.Assert(p.Parent().Title(), qt.Equals, "L1s")
239 c.Assert(len(p.Sections()), qt.Equals, 0)
240 c.Assert(len(p.Ancestors()), qt.Equals, 2)
241 }},
242 {"l1,l2,l3", func(c *qt.C, p page.Page) {
243 nilp, _ := p.GetPage("this/does/not/exist")
244
245 c.Assert(p.Title(), qt.Equals, "T3_-1")
246 c.Assert(len(p.Pages()), qt.Equals, 2)
247 c.Assert(p.Parent().Title(), qt.Equals, "T2_-1")
248 c.Assert(len(p.Sections()), qt.Equals, 0)
249 c.Assert(len(p.Ancestors()), qt.Equals, 3)
250
251 l1 := getPage(p, "/l1")
252 isDescendant := l1.IsDescendant(p)
253 c.Assert(isDescendant, qt.Equals, false)
254 isDescendant = l1.IsDescendant(nil)
255 c.Assert(isDescendant, qt.Equals, false)
256 isDescendant = nilp.IsDescendant(p)
257 c.Assert(isDescendant, qt.Equals, false)
258 isDescendant = p.IsDescendant(l1)
259 c.Assert(isDescendant, qt.Equals, true)
260
261 isAncestor := l1.IsAncestor(p)
262 c.Assert(isAncestor, qt.Equals, true)
263 isAncestor = p.IsAncestor(l1)
264 c.Assert(isAncestor, qt.Equals, false)
265 c.Assert(p.FirstSection(), qt.Equals, l1)
266 isAncestor = p.IsAncestor(nil)
267 c.Assert(isAncestor, qt.Equals, false)
268 c.Assert(isAncestor, qt.Equals, false)
269
270 l3 := getPage(p, "/l1/l2/l3")
271 c.Assert(l3.FirstSection(), qt.Equals, l1)
272 }},
273 {"perm a,link", func(c *qt.C, p page.Page) {
274 c.Assert(p.Title(), qt.Equals, "T9_-1")
275 c.Assert(p.RelPermalink(), qt.Equals, "/perm-a/link/")
276 c.Assert(len(p.Pages()), qt.Equals, 4)
277 first := p.Pages()[0]
278 c.Assert(first.RelPermalink(), qt.Equals, "/perm-a/link/t1_1/")
279 th.assertFileContent("public/perm-a/link/t1_1/index.html", "Single|T1_1")
280
281 last := p.Pages()[3]
282 c.Assert(last.RelPermalink(), qt.Equals, "/perm-a/link/t1_5/")
283 }},
284 }
285
286 home := s.getPageOldVersion(kinds.KindHome)
287
288 for _, test := range tests {
289 test := test
290 tt.Run(fmt.Sprintf("sections %s", test.sections), func(c *qt.C) {
291 c.Parallel()
292 sections := strings.Split(test.sections, ",")
293 p := s.getPageOldVersion(kinds.KindSection, sections...)
294 c.Assert(p, qt.Not(qt.IsNil), qt.Commentf(fmt.Sprint(sections)))
295
296 if p.Pages() != nil {
297 c.Assert(p.Data().(page.Data).Pages(), deepEqualsPages, p.Pages())
298 }
299 c.Assert(p.Parent(), qt.Not(qt.IsNil))
300 test.verify(c, p)
301 })
302 }
303
304 c.Assert(home, qt.Not(qt.IsNil))
305 c.Assert(len(home.Ancestors()), qt.Equals, 0)
306
307 c.Assert(len(home.Sections()), qt.Equals, 9)
308 c.Assert(s.Sections(), deepEqualsPages, home.Sections())
309
310 rootPage := s.getPageOldVersion(kinds.KindPage, "mypage.md")
311 c.Assert(rootPage, qt.Not(qt.IsNil))
312 c.Assert(rootPage.Parent().IsHome(), qt.Equals, true)
313 // https://github.com/gohugoio/hugo/issues/6365
314 c.Assert(rootPage.Sections(), qt.HasLen, 0)
315
316 sectionWithSpace := s.getPageOldVersion(kinds.KindSection, "Spaces in Section")
317 // s.h.pageTrees.debugPrint()
318 c.Assert(sectionWithSpace, qt.Not(qt.IsNil))
319 c.Assert(sectionWithSpace.RelPermalink(), qt.Equals, "/spaces-in-section/")
320
321 th.assertFileContent("public/l1/l2/page/2/index.html", "L1/l2-IsActive: true", "PAG|T2_3|true")
322 }
323
324 func TestNextInSectionNested(t *testing.T) {
325 t.Parallel()
326
327 pageContent := `---
328 title: "The Page"
329 weight: %d
330 ---
331 Some content.
332 `
333 createPageContent := func(weight int) string {
334 return fmt.Sprintf(pageContent, weight)
335 }
336
337 b := newTestSitesBuilder(t)
338 b.WithSimpleConfigFile()
339 b.WithTemplates("_default/single.html", `
340 Prev: {{ with .PrevInSection }}{{ .RelPermalink }}{{ end }}|
341 Next: {{ with .NextInSection }}{{ .RelPermalink }}{{ end }}|
342 `)
343
344 b.WithContent("blog/page1.md", createPageContent(1))
345 b.WithContent("blog/page2.md", createPageContent(2))
346 b.WithContent("blog/cool/_index.md", createPageContent(1))
347 b.WithContent("blog/cool/cool1.md", createPageContent(1))
348 b.WithContent("blog/cool/cool2.md", createPageContent(2))
349 b.WithContent("root1.md", createPageContent(1))
350 b.WithContent("root2.md", createPageContent(2))
351
352 b.Build(BuildCfg{})
353
354 b.AssertFileContent("public/root1/index.html",
355 "Prev: /root2/|", "Next: |")
356 b.AssertFileContent("public/root2/index.html",
357 "Prev: |", "Next: /root1/|")
358 b.AssertFileContent("public/blog/page1/index.html",
359 "Prev: /blog/page2/|", "Next: |")
360 b.AssertFileContent("public/blog/page2/index.html",
361 "Prev: |", "Next: /blog/page1/|")
362 b.AssertFileContent("public/blog/cool/cool1/index.html",
363 "Prev: /blog/cool/cool2/|", "Next: |")
364 b.AssertFileContent("public/blog/cool/cool2/index.html",
365 "Prev: |", "Next: /blog/cool/cool1/|")
366 }
367
368 func TestSectionEntries(t *testing.T) {
369 t.Parallel()
370
371 files := `
372 -- hugo.toml --
373 baseURL = "https://example.com/"
374 -- content/myfirstsection/p1.md --
375 ---
376 title: "P1"
377 ---
378 P1
379 -- content/a/b/c/_index.md --
380 ---
381 title: "C"
382 ---
383 C
384 -- content/a/b/c/mybundle/index.md --
385 ---
386 title: "My Bundle"
387 ---
388 -- layouts/_default/list.html --
389 Kind: {{ .Kind }}|RelPermalink: {{ .RelPermalink }}|SectionsPath: {{ .SectionsPath }}|SectionsEntries: {{ .SectionsEntries }}|Len: {{ len .SectionsEntries }}|
390 -- layouts/_default/single.html --
391 Kind: {{ .Kind }}|RelPermalink: {{ .RelPermalink }}|SectionsPath: {{ .SectionsPath }}|SectionsEntries: {{ .SectionsEntries }}|Len: {{ len .SectionsEntries }}|
392 `
393
394 b := Test(t, files)
395
396 b.AssertFileContent("public/myfirstsection/p1/index.html", "RelPermalink: /myfirstsection/p1/|SectionsPath: /myfirstsection|SectionsEntries: [myfirstsection]|Len: 1")
397 b.AssertFileContent("public/a/b/c/index.html", "RelPermalink: /a/b/c/|SectionsPath: /a/b/c|SectionsEntries: [a b c]|Len: 3")
398 b.AssertFileContent("public/a/b/c/mybundle/index.html", "Kind: page|RelPermalink: /a/b/c/mybundle/|SectionsPath: /a/b/c|SectionsEntries: [a b c]|Len: 3")
399 b.AssertFileContent("public/index.html", "Kind: home|RelPermalink: /|SectionsPath: /|SectionsEntries: []|Len: 0")
400 }
401
402 func TestParentWithPageOverlap(t *testing.T) {
403 files := `
404 -- hugo.toml --
405 baseURL = "https://example.com/"
406 -- content/docs/_index.md --
407 -- content/docs/logs/_index.md --
408 -- content/docs/logs/sdk.md --
409 -- content/docs/logs/sdk_exporters/stdout.md --
410 -- layouts/_default/list.html --
411 {{ .RelPermalink }}|{{ with .Parent}}{{ .RelPermalink }}{{ end }}|
412 -- layouts/_default/single.html --
413 {{ .RelPermalink }}|{{ with .Parent}}{{ .RelPermalink }}{{ end }}|
414
415 `
416 b := Test(t, files)
417
418 b.AssertFileContent("public/index.html", "/||")
419 b.AssertFileContent("public/docs/index.html", "/docs/|/|")
420 b.AssertFileContent("public/docs/logs/index.html", "/docs/logs/|/docs/|")
421 b.AssertFileContent("public/docs/logs/sdk/index.html", "/docs/logs/sdk/|/docs/logs/|")
422 b.AssertFileContent("public/docs/logs/sdk_exporters/stdout/index.html", "/docs/logs/sdk_exporters/stdout/|/docs/logs/|")
423 }