hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

site_sections_test.go (13645B)

    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/resources/page"
   25 )
   26 
   27 func TestNestedSections(t *testing.T) {
   28 	var (
   29 		c       = qt.New(t)
   30 		cfg, fs = newTestCfg()
   31 		th      = newTestHelper(cfg, fs, t)
   32 	)
   33 
   34 	cfg.Set("permalinks", map[string]string{
   35 		"perm a": ":sections/:title",
   36 	})
   37 
   38 	pageTemplate := `---
   39 title: T%d_%d
   40 ---
   41 Content
   42 `
   43 
   44 	// Home page
   45 	writeSource(t, fs, filepath.Join("content", "_index.md"), fmt.Sprintf(pageTemplate, -1, -1))
   46 
   47 	// Top level content page
   48 	writeSource(t, fs, filepath.Join("content", "mypage.md"), fmt.Sprintf(pageTemplate, 1234, 5))
   49 
   50 	// Top level section without index content page
   51 	writeSource(t, fs, filepath.Join("content", "top", "mypage2.md"), fmt.Sprintf(pageTemplate, 12345, 6))
   52 	// Just a page in a subfolder, i.e. not a section.
   53 	writeSource(t, fs, filepath.Join("content", "top", "folder", "mypage3.md"), fmt.Sprintf(pageTemplate, 12345, 67))
   54 
   55 	for level1 := 1; level1 < 3; level1++ {
   56 		writeSource(t, fs, filepath.Join("content", "l1", fmt.Sprintf("page_1_%d.md", level1)),
   57 			fmt.Sprintf(pageTemplate, 1, level1))
   58 	}
   59 
   60 	// Issue #3586
   61 	writeSource(t, fs, filepath.Join("content", "post", "0000.md"), fmt.Sprintf(pageTemplate, 1, 2))
   62 	writeSource(t, fs, filepath.Join("content", "post", "0000", "0001.md"), fmt.Sprintf(pageTemplate, 1, 3))
   63 	writeSource(t, fs, filepath.Join("content", "elsewhere", "0003.md"), fmt.Sprintf(pageTemplate, 1, 4))
   64 
   65 	// Empty nested section, i.e. no regular content pages.
   66 	writeSource(t, fs, filepath.Join("content", "empty1", "b", "c", "_index.md"), fmt.Sprintf(pageTemplate, 33, -1))
   67 	// Index content file a the end and in the middle.
   68 	writeSource(t, fs, filepath.Join("content", "empty2", "b", "_index.md"), fmt.Sprintf(pageTemplate, 40, -1))
   69 	writeSource(t, fs, filepath.Join("content", "empty2", "b", "c", "d", "_index.md"), fmt.Sprintf(pageTemplate, 41, -1))
   70 
   71 	// Empty with content file in the middle.
   72 	writeSource(t, fs, filepath.Join("content", "empty3", "b", "c", "d", "_index.md"), fmt.Sprintf(pageTemplate, 41, -1))
   73 	writeSource(t, fs, filepath.Join("content", "empty3", "b", "empty3.md"), fmt.Sprintf(pageTemplate, 3, -1))
   74 
   75 	// Section with permalink config
   76 	writeSource(t, fs, filepath.Join("content", "perm a", "link", "_index.md"), fmt.Sprintf(pageTemplate, 9, -1))
   77 	for i := 1; i < 4; i++ {
   78 		writeSource(t, fs, filepath.Join("content", "perm a", "link", fmt.Sprintf("page_%d.md", i)),
   79 			fmt.Sprintf(pageTemplate, 1, i))
   80 	}
   81 	writeSource(t, fs, filepath.Join("content", "perm a", "link", "regular", fmt.Sprintf("page_%d.md", 5)),
   82 		fmt.Sprintf(pageTemplate, 1, 5))
   83 
   84 	writeSource(t, fs, filepath.Join("content", "l1", "l2", "_index.md"), fmt.Sprintf(pageTemplate, 2, -1))
   85 	writeSource(t, fs, filepath.Join("content", "l1", "l2_2", "_index.md"), fmt.Sprintf(pageTemplate, 22, -1))
   86 	writeSource(t, fs, filepath.Join("content", "l1", "l2", "l3", "_index.md"), fmt.Sprintf(pageTemplate, 3, -1))
   87 
   88 	for level2 := 1; level2 < 4; level2++ {
   89 		writeSource(t, fs, filepath.Join("content", "l1", "l2", fmt.Sprintf("page_2_%d.md", level2)),
   90 			fmt.Sprintf(pageTemplate, 2, level2))
   91 	}
   92 	for level2 := 1; level2 < 3; level2++ {
   93 		writeSource(t, fs, filepath.Join("content", "l1", "l2_2", fmt.Sprintf("page_2_2_%d.md", level2)),
   94 			fmt.Sprintf(pageTemplate, 2, level2))
   95 	}
   96 	for level3 := 1; level3 < 3; level3++ {
   97 		writeSource(t, fs, filepath.Join("content", "l1", "l2", "l3", fmt.Sprintf("page_3_%d.md", level3)),
   98 			fmt.Sprintf(pageTemplate, 3, level3))
   99 	}
  100 
  101 	writeSource(t, fs, filepath.Join("content", "Spaces in Section", "page100.md"), fmt.Sprintf(pageTemplate, 10, 0))
  102 
  103 	writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), "<html>Single|{{ .Title }}</html>")
  104 	writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"),
  105 		`
  106 {{ $sect := (.Site.GetPage "l1/l2") }}
  107 <html>List|{{ .Title }}|L1/l2-IsActive: {{ .InSection $sect }}
  108 {{ range .Paginator.Pages }}
  109 PAG|{{ .Title }}|{{ $sect.InSection . }}
  110 {{ end }}
  111 {{/* https://github.com/gohugoio/hugo/issues/4989 */}}
  112 {{ $sections := (.Site.GetPage "section" .Section).Sections.ByWeight }}
  113 </html>`)
  114 
  115 	cfg.Set("paginate", 2)
  116 
  117 	s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
  118 
  119 	c.Assert(len(s.RegularPages()), qt.Equals, 21)
  120 
  121 	tests := []struct {
  122 		sections string
  123 		verify   func(c *qt.C, p page.Page)
  124 	}{
  125 		{"elsewhere", func(c *qt.C, p page.Page) {
  126 			c.Assert(len(p.Pages()), qt.Equals, 1)
  127 			for _, p := range p.Pages() {
  128 				c.Assert(p.SectionsPath(), qt.Equals, "elsewhere")
  129 			}
  130 		}},
  131 		{"post", func(c *qt.C, p page.Page) {
  132 			c.Assert(len(p.Pages()), qt.Equals, 2)
  133 			for _, p := range p.Pages() {
  134 				c.Assert(p.Section(), qt.Equals, "post")
  135 			}
  136 		}},
  137 		{"empty1", func(c *qt.C, p page.Page) {
  138 			// > b,c
  139 			c.Assert(getPage(p, "/empty1/b"), qt.IsNil) // No _index.md page.
  140 			c.Assert(getPage(p, "/empty1/b/c"), qt.Not(qt.IsNil))
  141 		}},
  142 		{"empty2", func(c *qt.C, p page.Page) {
  143 			// > b,c,d where b and d have _index.md files.
  144 			b := getPage(p, "/empty2/b")
  145 			c.Assert(b, qt.Not(qt.IsNil))
  146 			c.Assert(b.Title(), qt.Equals, "T40_-1")
  147 
  148 			cp := getPage(p, "/empty2/b/c")
  149 			c.Assert(cp, qt.IsNil) // No _index.md
  150 
  151 			d := getPage(p, "/empty2/b/c/d")
  152 			c.Assert(d, qt.Not(qt.IsNil))
  153 			c.Assert(d.Title(), qt.Equals, "T41_-1")
  154 
  155 			c.Assert(cp.Eq(d), qt.Equals, false)
  156 			c.Assert(cp.Eq(cp), qt.Equals, true)
  157 			c.Assert(cp.Eq("asdf"), qt.Equals, false)
  158 		}},
  159 		{"empty3", func(c *qt.C, p page.Page) {
  160 			// b,c,d with regular page in b
  161 			b := getPage(p, "/empty3/b")
  162 			c.Assert(b, qt.IsNil) // No _index.md
  163 			e3 := getPage(p, "/empty3/b/empty3")
  164 			c.Assert(e3, qt.Not(qt.IsNil))
  165 			c.Assert(e3.File().LogicalName(), qt.Equals, "empty3.md")
  166 		}},
  167 		{"empty3", func(c *qt.C, p page.Page) {
  168 			xxx := getPage(p, "/empty3/nil")
  169 			c.Assert(xxx, qt.IsNil)
  170 		}},
  171 		{"top", func(c *qt.C, p page.Page) {
  172 			c.Assert(p.Title(), qt.Equals, "Tops")
  173 			c.Assert(len(p.Pages()), qt.Equals, 2)
  174 			c.Assert(p.Pages()[0].File().LogicalName(), qt.Equals, "mypage2.md")
  175 			c.Assert(p.Pages()[1].File().LogicalName(), qt.Equals, "mypage3.md")
  176 			home := p.Parent()
  177 			c.Assert(home.IsHome(), qt.Equals, true)
  178 			c.Assert(len(p.Sections()), qt.Equals, 0)
  179 			c.Assert(home.CurrentSection(), qt.Equals, home)
  180 			active, err := home.InSection(home)
  181 			c.Assert(err, qt.IsNil)
  182 			c.Assert(active, qt.Equals, true)
  183 			c.Assert(p.FirstSection(), qt.Equals, p)
  184 		}},
  185 		{"l1", func(c *qt.C, p page.Page) {
  186 			c.Assert(p.Title(), qt.Equals, "L1s")
  187 			c.Assert(len(p.Pages()), qt.Equals, 4) // 2 pages + 2 sections
  188 			c.Assert(p.Parent().IsHome(), qt.Equals, true)
  189 			c.Assert(len(p.Sections()), qt.Equals, 2)
  190 		}},
  191 		{"l1,l2", func(c *qt.C, p page.Page) {
  192 			c.Assert(p.Title(), qt.Equals, "T2_-1")
  193 			c.Assert(len(p.Pages()), qt.Equals, 4) // 3 pages + 1 section
  194 			c.Assert(p.Pages()[0].Parent(), qt.Equals, p)
  195 			c.Assert(p.Parent().Title(), qt.Equals, "L1s")
  196 			c.Assert(p.RelPermalink(), qt.Equals, "/l1/l2/")
  197 			c.Assert(len(p.Sections()), qt.Equals, 1)
  198 
  199 			for _, child := range p.Pages() {
  200 				if child.IsSection() {
  201 					c.Assert(child.CurrentSection(), qt.Equals, child)
  202 					continue
  203 				}
  204 
  205 				c.Assert(child.CurrentSection(), qt.Equals, p)
  206 				active, err := child.InSection(p)
  207 				c.Assert(err, qt.IsNil)
  208 
  209 				c.Assert(active, qt.Equals, true)
  210 				active, err = p.InSection(child)
  211 				c.Assert(err, qt.IsNil)
  212 				c.Assert(active, qt.Equals, true)
  213 				active, err = p.InSection(getPage(p, "/"))
  214 				c.Assert(err, qt.IsNil)
  215 				c.Assert(active, qt.Equals, false)
  216 
  217 				isAncestor, err := p.IsAncestor(child)
  218 				c.Assert(err, qt.IsNil)
  219 				c.Assert(isAncestor, qt.Equals, true)
  220 				isAncestor, err = child.IsAncestor(p)
  221 				c.Assert(err, qt.IsNil)
  222 				c.Assert(isAncestor, qt.Equals, false)
  223 
  224 				isDescendant, err := p.IsDescendant(child)
  225 				c.Assert(err, qt.IsNil)
  226 				c.Assert(isDescendant, qt.Equals, false)
  227 				isDescendant, err = child.IsDescendant(p)
  228 				c.Assert(err, qt.IsNil)
  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 		}},
  241 		{"l1,l2,l3", func(c *qt.C, p page.Page) {
  242 			nilp, _ := p.GetPage("this/does/not/exist")
  243 
  244 			c.Assert(p.Title(), qt.Equals, "T3_-1")
  245 			c.Assert(len(p.Pages()), qt.Equals, 2)
  246 			c.Assert(p.Parent().Title(), qt.Equals, "T2_-1")
  247 			c.Assert(len(p.Sections()), qt.Equals, 0)
  248 
  249 			l1 := getPage(p, "/l1")
  250 			isDescendant, err := l1.IsDescendant(p)
  251 			c.Assert(err, qt.IsNil)
  252 			c.Assert(isDescendant, qt.Equals, false)
  253 			isDescendant, err = l1.IsDescendant(nil)
  254 			c.Assert(err, qt.IsNil)
  255 			c.Assert(isDescendant, qt.Equals, false)
  256 			isDescendant, err = nilp.IsDescendant(p)
  257 			c.Assert(err, qt.IsNil)
  258 			c.Assert(isDescendant, qt.Equals, false)
  259 			isDescendant, err = p.IsDescendant(l1)
  260 			c.Assert(err, qt.IsNil)
  261 			c.Assert(isDescendant, qt.Equals, true)
  262 
  263 			isAncestor, err := l1.IsAncestor(p)
  264 			c.Assert(err, qt.IsNil)
  265 			c.Assert(isAncestor, qt.Equals, true)
  266 			isAncestor, err = p.IsAncestor(l1)
  267 			c.Assert(err, qt.IsNil)
  268 			c.Assert(isAncestor, qt.Equals, false)
  269 			c.Assert(p.FirstSection(), qt.Equals, l1)
  270 			isAncestor, err = p.IsAncestor(nil)
  271 			c.Assert(err, qt.IsNil)
  272 			c.Assert(isAncestor, qt.Equals, false)
  273 			isAncestor, err = nilp.IsAncestor(l1)
  274 			c.Assert(err, qt.IsNil)
  275 			c.Assert(isAncestor, qt.Equals, false)
  276 		}},
  277 		{"perm a,link", func(c *qt.C, p page.Page) {
  278 			c.Assert(p.Title(), qt.Equals, "T9_-1")
  279 			c.Assert(p.RelPermalink(), qt.Equals, "/perm-a/link/")
  280 			c.Assert(len(p.Pages()), qt.Equals, 4)
  281 			first := p.Pages()[0]
  282 			c.Assert(first.RelPermalink(), qt.Equals, "/perm-a/link/t1_1/")
  283 			th.assertFileContent("public/perm-a/link/t1_1/index.html", "Single|T1_1")
  284 
  285 			last := p.Pages()[3]
  286 			c.Assert(last.RelPermalink(), qt.Equals, "/perm-a/link/t1_5/")
  287 		}},
  288 	}
  289 
  290 	home := s.getPage(page.KindHome)
  291 
  292 	for _, test := range tests {
  293 		test := test
  294 		t.Run(fmt.Sprintf("sections %s", test.sections), func(t *testing.T) {
  295 			t.Parallel()
  296 			c := qt.New(t)
  297 			sections := strings.Split(test.sections, ",")
  298 			p := s.getPage(page.KindSection, sections...)
  299 			c.Assert(p, qt.Not(qt.IsNil), qt.Commentf(fmt.Sprint(sections)))
  300 
  301 			if p.Pages() != nil {
  302 				c.Assert(p.Data().(page.Data).Pages(), deepEqualsPages, p.Pages())
  303 			}
  304 			c.Assert(p.Parent(), qt.Not(qt.IsNil))
  305 			test.verify(c, p)
  306 		})
  307 	}
  308 
  309 	c.Assert(home, qt.Not(qt.IsNil))
  310 
  311 	c.Assert(len(home.Sections()), qt.Equals, 9)
  312 	c.Assert(s.Info.Sections(), deepEqualsPages, home.Sections())
  313 
  314 	rootPage := s.getPage(page.KindPage, "mypage.md")
  315 	c.Assert(rootPage, qt.Not(qt.IsNil))
  316 	c.Assert(rootPage.Parent().IsHome(), qt.Equals, true)
  317 	// https://github.com/gohugoio/hugo/issues/6365
  318 	c.Assert(rootPage.Sections(), qt.HasLen, 0)
  319 
  320 	// Add a odd test for this as this looks a little bit off, but I'm not in the mood
  321 	// to think too hard a out this right now. It works, but people will have to spell
  322 	// out the directory name as is.
  323 	// If we later decide to do something about this, we will have to do some normalization in
  324 	// getPage.
  325 	// TODO(bep)
  326 	sectionWithSpace := s.getPage(page.KindSection, "Spaces in Section")
  327 	c.Assert(sectionWithSpace, qt.Not(qt.IsNil))
  328 	c.Assert(sectionWithSpace.RelPermalink(), qt.Equals, "/spaces-in-section/")
  329 
  330 	th.assertFileContent("public/l1/l2/page/2/index.html", "L1/l2-IsActive: true", "PAG|T2_3|true")
  331 }
  332 
  333 func TestNextInSectionNested(t *testing.T) {
  334 	t.Parallel()
  335 
  336 	pageContent := `---
  337 title: "The Page"
  338 weight: %d
  339 ---
  340 Some content.
  341 `
  342 	createPageContent := func(weight int) string {
  343 		return fmt.Sprintf(pageContent, weight)
  344 	}
  345 
  346 	b := newTestSitesBuilder(t)
  347 	b.WithSimpleConfigFile()
  348 	b.WithTemplates("_default/single.html", `
  349 Prev: {{ with .PrevInSection }}{{ .RelPermalink }}{{ end }}|
  350 Next: {{ with .NextInSection }}{{ .RelPermalink }}{{ end }}|
  351 `)
  352 
  353 	b.WithContent("blog/page1.md", createPageContent(1))
  354 	b.WithContent("blog/page2.md", createPageContent(2))
  355 	b.WithContent("blog/cool/_index.md", createPageContent(1))
  356 	b.WithContent("blog/cool/cool1.md", createPageContent(1))
  357 	b.WithContent("blog/cool/cool2.md", createPageContent(2))
  358 	b.WithContent("root1.md", createPageContent(1))
  359 	b.WithContent("root2.md", createPageContent(2))
  360 
  361 	b.Build(BuildCfg{})
  362 
  363 	b.AssertFileContent("public/root1/index.html",
  364 		"Prev: /root2/|", "Next: |")
  365 	b.AssertFileContent("public/root2/index.html",
  366 		"Prev: |", "Next: /root1/|")
  367 	b.AssertFileContent("public/blog/page1/index.html",
  368 		"Prev: /blog/page2/|", "Next: |")
  369 	b.AssertFileContent("public/blog/page2/index.html",
  370 		"Prev: |", "Next: /blog/page1/|")
  371 	b.AssertFileContent("public/blog/cool/cool1/index.html",
  372 		"Prev: /blog/cool/cool2/|", "Next: |")
  373 	b.AssertFileContent("public/blog/cool/cool2/index.html",
  374 		"Prev: |", "Next: /blog/cool/cool1/|")
  375 }