github.com/neohugo/neohugo@v0.123.8/hugolib/taxonomy_test.go (about)

     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  	"reflect"
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/neohugo/neohugo/resources/kinds"
    24  	"github.com/neohugo/neohugo/resources/page"
    25  
    26  	qt "github.com/frankban/quicktest"
    27  
    28  	"github.com/neohugo/neohugo/deps"
    29  )
    30  
    31  func TestTaxonomiesCountOrder(t *testing.T) {
    32  	t.Parallel()
    33  	c := qt.New(t)
    34  
    35  	taxonomies := make(map[string]string)
    36  	taxonomies["tag"] = "tags"
    37  	taxonomies["category"] = "categories"
    38  
    39  	cfg, fs := newTestCfg()
    40  
    41  	cfg.Set("titleCaseStyle", "none")
    42  	cfg.Set("taxonomies", taxonomies)
    43  	configs, err := loadTestConfigFromProvider(cfg)
    44  	c.Assert(err, qt.IsNil)
    45  
    46  	const pageContent = `---
    47  tags: ['a', 'B', 'c']
    48  categories: 'd'
    49  ---
    50  YAML frontmatter with tags and categories taxonomy.`
    51  
    52  	writeSource(t, fs, filepath.Join("content", "page.md"), pageContent)
    53  
    54  	s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Configs: configs}, BuildCfg{})
    55  
    56  	st := make([]string, 0)
    57  	for _, t := range s.Taxonomies()["tags"].ByCount() {
    58  		st = append(st, t.Page().Title()+":"+t.Name)
    59  	}
    60  
    61  	expect := []string{"a:a", "B:b", "c:c"}
    62  
    63  	if !reflect.DeepEqual(st, expect) {
    64  		t.Fatalf("ordered taxonomies mismatch, expected\n%v\ngot\n%q", expect, st)
    65  	}
    66  }
    67  
    68  func TestTaxonomiesWithAndWithoutContentFile(t *testing.T) {
    69  	for _, uglyURLs := range []bool{false, true} {
    70  		uglyURLs := uglyURLs
    71  		t.Run(fmt.Sprintf("uglyURLs=%t", uglyURLs), func(t *testing.T) {
    72  			t.Parallel()
    73  			doTestTaxonomiesWithAndWithoutContentFile(t, uglyURLs)
    74  		})
    75  	}
    76  }
    77  
    78  func doTestTaxonomiesWithAndWithoutContentFile(t *testing.T, uglyURLs bool) {
    79  	siteConfig := `
    80  baseURL = "http://example.com/blog"
    81  titleCaseStyle = "firstupper"
    82  uglyURLs = %t
    83  paginate = 1
    84  defaultContentLanguage = "en"
    85  [Taxonomies]
    86  tag = "tags"
    87  category = "categories"
    88  other = "others"
    89  empty = "empties"
    90  permalinked = "permalinkeds"
    91  [permalinks]
    92  permalinkeds = "/perma/:slug/"
    93  `
    94  
    95  	pageTemplate := `---
    96  title: "%s"
    97  tags:
    98  %s
    99  categories:
   100  %s
   101  others:
   102  %s
   103  permalinkeds:
   104  %s
   105  ---
   106  # Doc
   107  `
   108  
   109  	siteConfig = fmt.Sprintf(siteConfig, uglyURLs)
   110  
   111  	b := newTestSitesBuilder(t).WithConfigFile("toml", siteConfig)
   112  
   113  	b.WithContent(
   114  		"p1.md", fmt.Sprintf(pageTemplate, "t1/c1", "- Tag1", "- cAt1", "- o1", "- Pl1"),
   115  		"p2.md", fmt.Sprintf(pageTemplate, "t2/c1", "- tag2", "- cAt1", "- o1", "- Pl1"),
   116  		"p3.md", fmt.Sprintf(pageTemplate, "t2/c12", "- tag2", "- cat2", "- o1", "- Pl1"),
   117  		"p4.md", fmt.Sprintf(pageTemplate, "Hello World", "", "", "- \"Hello Hugo world\"", "- Pl1"),
   118  		"categories/_index.md", newTestPage("Category Terms", "2017-01-01", 10),
   119  		"tags/Tag1/_index.md", newTestPage("Tag1 List", "2017-01-01", 10),
   120  		// https://github.com/gohugoio/hugo/issues/5847
   121  		"/tags/not-used/_index.md", newTestPage("Unused Tag List", "2018-01-01", 10),
   122  	)
   123  
   124  	b.Build(BuildCfg{})
   125  
   126  	// So what we have now is:
   127  	// 1. categories with terms content page, but no content page for the only c1 category
   128  	// 2. tags with no terms content page, but content page for one of 2 tags (tag1)
   129  	// 3. the "others" taxonomy with no content pages.
   130  	// 4. the "permalinkeds" taxonomy with permalinks configuration.
   131  
   132  	pathFunc := func(s string) string {
   133  		if uglyURLs {
   134  			return strings.Replace(s, "/index.html", ".html", 1)
   135  		}
   136  		return s
   137  	}
   138  
   139  	// 1.
   140  	b.AssertFileContent(pathFunc("public/categories/cat1/index.html"), "List", "CAt1")
   141  	b.AssertFileContent(pathFunc("public/categories/index.html"), "Taxonomy Term Page", "Category Terms")
   142  
   143  	// 2.
   144  	b.AssertFileContent(pathFunc("public/tags/tag2/index.html"), "List", "tag2")
   145  	b.AssertFileContent(pathFunc("public/tags/tag1/index.html"), "List", "Tag1")
   146  	b.AssertFileContent(pathFunc("public/tags/index.html"), "Taxonomy Term Page", "Tags")
   147  
   148  	// 3.
   149  	b.AssertFileContent(pathFunc("public/others/o1/index.html"), "List", "o1")
   150  	b.AssertFileContent(pathFunc("public/others/index.html"), "Taxonomy Term Page", "Others")
   151  
   152  	// 4.
   153  	b.AssertFileContent(pathFunc("public/perma/pl1/index.html"), "List", "Pl1")
   154  
   155  	// This looks kind of funky, but the taxonomy terms do not have a permalinks definition,
   156  	// for good reasons.
   157  	b.AssertFileContent(pathFunc("public/permalinkeds/index.html"), "Taxonomy Term Page", "Permalinkeds")
   158  
   159  	s := b.H.Sites[0]
   160  
   161  	// Make sure that each kinds.KindTaxonomyTerm page has an appropriate number
   162  	// of kinds.KindTaxonomy pages in its Pages slice.
   163  	taxonomyTermPageCounts := map[string]int{
   164  		"tags":         3,
   165  		"categories":   2,
   166  		"others":       2,
   167  		"empties":      0,
   168  		"permalinkeds": 1,
   169  	}
   170  
   171  	for taxonomy, count := range taxonomyTermPageCounts {
   172  		msg := qt.Commentf(taxonomy)
   173  		term := s.getPageOldVersion(kinds.KindTaxonomy, taxonomy)
   174  		b.Assert(term, qt.Not(qt.IsNil), msg)
   175  		b.Assert(len(term.Pages()), qt.Equals, count, msg)
   176  
   177  		for _, p := range term.Pages() {
   178  			b.Assert(p.Kind(), qt.Equals, kinds.KindTerm)
   179  		}
   180  	}
   181  
   182  	cat1 := s.getPageOldVersion(kinds.KindTerm, "categories", "cat1")
   183  	b.Assert(cat1, qt.Not(qt.IsNil))
   184  	if uglyURLs {
   185  		b.Assert(cat1.RelPermalink(), qt.Equals, "/blog/categories/cat1.html")
   186  	} else {
   187  		b.Assert(cat1.RelPermalink(), qt.Equals, "/blog/categories/cat1/")
   188  	}
   189  
   190  	pl1 := s.getPageOldVersion(kinds.KindTerm, "permalinkeds", "pl1")
   191  	permalinkeds := s.getPageOldVersion(kinds.KindTaxonomy, "permalinkeds")
   192  	b.Assert(pl1, qt.Not(qt.IsNil))
   193  	b.Assert(permalinkeds, qt.Not(qt.IsNil))
   194  	if uglyURLs {
   195  		b.Assert(pl1.RelPermalink(), qt.Equals, "/blog/perma/pl1.html")
   196  		b.Assert(permalinkeds.RelPermalink(), qt.Equals, "/blog/permalinkeds.html")
   197  	} else {
   198  		b.Assert(pl1.RelPermalink(), qt.Equals, "/blog/perma/pl1/")
   199  		b.Assert(permalinkeds.RelPermalink(), qt.Equals, "/blog/permalinkeds/")
   200  	}
   201  
   202  	helloWorld := s.getPageOldVersion(kinds.KindTerm, "others", "hello-hugo-world")
   203  	b.Assert(helloWorld, qt.Not(qt.IsNil))
   204  	b.Assert(helloWorld.Title(), qt.Equals, "Hello Hugo world")
   205  
   206  	// Issue #2977
   207  	b.AssertFileContent(pathFunc("public/empties/index.html"), "Taxonomy Term Page", "Empties")
   208  }
   209  
   210  // https://github.com/gohugoio/hugo/issues/5513
   211  // https://github.com/gohugoio/hugo/issues/5571
   212  func TestTaxonomiesPathSeparation(t *testing.T) {
   213  	t.Parallel()
   214  
   215  	config := `
   216  baseURL = "https://example.com"
   217  titleCaseStyle = "none"
   218  [taxonomies]
   219  "news/tag" = "news/tags"
   220  "news/category" = "news/categories"
   221  "t1/t2/t3" = "t1/t2/t3s"
   222  "s1/s2/s3" = "s1/s2/s3s"
   223  `
   224  
   225  	pageContent := `
   226  +++
   227  title = "foo"
   228  "news/categories" = ["a", "b", "c", "d/e", "f/g/h"]
   229  "t1/t2/t3s" = ["t4/t5", "t4/t5/t6"]
   230  +++
   231  Content.
   232  `
   233  
   234  	b := newTestSitesBuilder(t)
   235  	b.WithConfigFile("toml", config)
   236  	b.WithContent("page.md", pageContent)
   237  	b.WithContent("news/categories/b/_index.md", `
   238  ---
   239  title: "This is B"
   240  ---
   241  `)
   242  
   243  	b.WithContent("news/categories/f/g/h/_index.md", `
   244  ---
   245  title: "This is H"
   246  ---
   247  `)
   248  
   249  	b.WithContent("t1/t2/t3s/t4/t5/_index.md", `
   250  ---
   251  title: "This is T5"
   252  ---
   253  `)
   254  
   255  	b.WithContent("s1/s2/s3s/_index.md", `
   256  ---
   257  title: "This is S3s"
   258  ---
   259  `)
   260  
   261  	b.CreateSites().Build(BuildCfg{})
   262  
   263  	s := b.H.Sites[0]
   264  
   265  	filterbyKind := func(kind string) page.Pages {
   266  		var pages page.Pages
   267  		for _, p := range s.Pages() {
   268  			if p.Kind() == kind {
   269  				pages = append(pages, p)
   270  			}
   271  		}
   272  		return pages
   273  	}
   274  
   275  	ta := filterbyKind(kinds.KindTerm)
   276  	te := filterbyKind(kinds.KindTaxonomy)
   277  
   278  	b.Assert(len(te), qt.Equals, 4)
   279  	b.Assert(len(ta), qt.Equals, 7)
   280  
   281  	b.AssertFileContent("public/news/categories/a/index.html", "Taxonomy List Page 1|a|Hello|https://example.com/news/categories/a/|")
   282  	b.AssertFileContent("public/news/categories/b/index.html", "Taxonomy List Page 1|This is B|Hello|https://example.com/news/categories/b/|")
   283  	b.AssertFileContent("public/news/categories/d/e/index.html", "Taxonomy List Page 1|d/e|Hello|https://example.com/news/categories/d/e/|")
   284  	b.AssertFileContent("public/news/categories/f/g/h/index.html", "Taxonomy List Page 1|This is H|Hello|https://example.com/news/categories/f/g/h/|")
   285  	b.AssertFileContent("public/t1/t2/t3s/t4/t5/index.html", "Taxonomy List Page 1|This is T5|Hello|https://example.com/t1/t2/t3s/t4/t5/|")
   286  	b.AssertFileContent("public/t1/t2/t3s/t4/t5/t6/index.html", "Taxonomy List Page 1|t4/t5/t6|Hello|https://example.com/t1/t2/t3s/t4/t5/t6/|")
   287  
   288  	b.AssertFileContent("public/news/categories/index.html", "Taxonomy Term Page 1|categories|Hello|https://example.com/news/categories/|")
   289  	b.AssertFileContent("public/t1/t2/t3s/index.html", "Taxonomy Term Page 1|t3s|Hello|https://example.com/t1/t2/t3s/|")
   290  	b.AssertFileContent("public/s1/s2/s3s/index.html", "Taxonomy Term Page 1|This is S3s|Hello|https://example.com/s1/s2/s3s/|")
   291  }
   292  
   293  // https://github.com/gohugoio/hugo/issues/5719
   294  func TestTaxonomiesNextGenLoops(t *testing.T) {
   295  	b := newTestSitesBuilder(t).WithSimpleConfigFile()
   296  
   297  	b.WithTemplatesAdded("index.html", `
   298  <h1>Tags</h1>
   299  <ul>
   300      {{ range .Site.Taxonomies.tags }}
   301              <li><a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a> {{ .Count }}</li>
   302      {{ end }}
   303  </ul>
   304  
   305  `)
   306  
   307  	b.WithTemplatesAdded("_default/terms.html", `
   308  <h1>Terms</h1>
   309  <ul>
   310      {{ range .Data.Terms.Alphabetical }}
   311              <li><a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a> {{ .Count }}</li>
   312      {{ end }}
   313  </ul>
   314  `)
   315  
   316  	for i := 0; i < 10; i++ {
   317  		b.WithContent(fmt.Sprintf("page%d.md", i+1), `
   318  ---
   319  Title: "Taxonomy!"
   320  tags: ["Hugo Rocks!", "Rocks I say!" ]
   321  categories: ["This is Cool", "And new" ]
   322  ---
   323  
   324  Content.
   325  
   326  		`)
   327  	}
   328  
   329  	b.CreateSites().Build(BuildCfg{})
   330  
   331  	b.AssertFileContent("public/index.html", `<li><a href="http://example.com/tags/hugo-rocks/">Hugo Rocks!</a> 10</li>`)
   332  	b.AssertFileContent("public/categories/index.html", `<li><a href="http://example.com/categories/this-is-cool/">This Is Cool</a> 10</li>`)
   333  	b.AssertFileContent("public/tags/index.html", `<li><a href="http://example.com/tags/rocks-i-say/">Rocks I Say!</a> 10</li>`)
   334  }
   335  
   336  // Issue 6213
   337  func TestTaxonomiesNotForDrafts(t *testing.T) {
   338  	t.Parallel()
   339  
   340  	b := newTestSitesBuilder(t)
   341  	b.WithContent("draft.md", `---
   342  title: "Draft"
   343  draft: true
   344  categories: ["drafts"]
   345  ---
   346  
   347  `,
   348  		"regular.md", `---
   349  title: "Not Draft"
   350  categories: ["regular"]
   351  ---
   352  
   353  `)
   354  
   355  	b.Build(BuildCfg{})
   356  	s := b.H.Sites[0]
   357  
   358  	b.Assert(b.CheckExists("public/categories/regular/index.html"), qt.Equals, true)
   359  	b.Assert(b.CheckExists("public/categories/drafts/index.html"), qt.Equals, false)
   360  
   361  	reg, _ := s.getPage(nil, "categories/regular")
   362  	dra, _ := s.getPage(nil, "categories/draft")
   363  	b.Assert(reg, qt.Not(qt.IsNil))
   364  	b.Assert(dra, qt.IsNil)
   365  }
   366  
   367  func TestTaxonomiesIndexDraft(t *testing.T) {
   368  	t.Parallel()
   369  	b := newTestSitesBuilder(t)
   370  	b.WithContent(
   371  		"categories/_index.md", `---
   372  title: "The Categories"
   373  draft: true
   374  ---
   375  
   376  Content.
   377  
   378  `,
   379  		"page.md", `---
   380  title: "The Page"
   381  categories: ["cool"]
   382  ---
   383  
   384  Content.
   385  
   386  `,
   387  	)
   388  
   389  	b.WithTemplates("index.html", `
   390  {{ range .Site.Pages }}
   391  {{ .RelPermalink }}|{{ .Title }}|{{ .WordCount }}|{{ .Content }}|
   392  {{ end }}
   393  `)
   394  
   395  	b.Build(BuildCfg{})
   396  
   397  	b.AssertFileContentFn("public/index.html", func(s string) bool {
   398  		return !strings.Contains(s, "/categories/|")
   399  	})
   400  }
   401  
   402  // https://github.com/gohugoio/hugo/issues/6927
   403  func TestTaxonomiesHomeDraft(t *testing.T) {
   404  	t.Parallel()
   405  
   406  	b := newTestSitesBuilder(t)
   407  	b.WithContent(
   408  		"_index.md", `---
   409  title: "Home"
   410  draft: true
   411  ---
   412  
   413  Content.
   414  
   415  `,
   416  		"posts/_index.md", `---
   417  title: "Posts"
   418  draft: true
   419  ---
   420  
   421  Content.
   422  
   423  `,
   424  		"posts/page.md", `---
   425  title: "The Page"
   426  categories: ["cool"]
   427  ---
   428  
   429  Content.
   430  
   431  `,
   432  	)
   433  
   434  	b.WithTemplates("index.html", `
   435  NO HOME FOR YOU
   436  `)
   437  
   438  	b.Build(BuildCfg{})
   439  
   440  	b.Assert(b.CheckExists("public/index.html"), qt.Equals, false)
   441  	b.Assert(b.CheckExists("public/categories/index.html"), qt.Equals, false)
   442  	b.Assert(b.CheckExists("public/posts/index.html"), qt.Equals, false)
   443  }
   444  
   445  // https://github.com/gohugoio/hugo/issues/6173
   446  func TestTaxonomiesWithBundledResources(t *testing.T) {
   447  	b := newTestSitesBuilder(t)
   448  	b.WithTemplates("_default/list.html", `
   449  List {{ .Title }}:
   450  {{ range .Resources }}
   451  Resource: {{ .RelPermalink }}|{{ .MediaType }}
   452  {{ end }}
   453  	`)
   454  
   455  	b.WithContent("p1.md", `---
   456  title: Page
   457  categories: ["funny"]
   458  ---
   459  	`,
   460  		"categories/_index.md", "---\ntitle: Categories Page\n---",
   461  		"categories/data.json", "Category data",
   462  		"categories/funny/_index.md", "---\ntitle: Funny Category\n---",
   463  		"categories/funny/funnydata.json", "Category funny data",
   464  	)
   465  
   466  	b.Build(BuildCfg{})
   467  
   468  	b.AssertFileContent("public/categories/index.html", `Resource: /categories/data.json|application/json`)
   469  	b.AssertFileContent("public/categories/funny/index.html", `Resource: /categories/funny/funnydata.json|application/json`)
   470  }
   471  
   472  func TestTaxonomiesRemoveOne(t *testing.T) {
   473  	files := `
   474  -- hugo.toml --
   475  disableLiveReload = true
   476  -- layouts/index.html --
   477  {{ $cats := .Site.Taxonomies.categories.cats }}
   478  {{ if $cats }}
   479  Len cats: {{ len $cats }}
   480  {{ range $cats }}
   481  	Cats:|{{ .Page.RelPermalink }}|
   482  {{ end }}
   483  {{ end }}
   484  {{ $funny := .Site.Taxonomies.categories.funny }}
   485  {{ if $funny }}
   486  Len funny: {{ len $funny }}
   487  {{ range $funny }}
   488  	Funny:|{{ .Page.RelPermalink }}|
   489  {{ end }}
   490  {{ end }}
   491  -- content/p1.md --
   492  ---
   493  title: Page
   494  categories: ["funny", "cats"]
   495  ---
   496  -- content/p2.md --
   497  ---
   498  title: Page2
   499  categories: ["funny", "cats"]
   500  ---
   501  
   502  `
   503  	b := TestRunning(t, files)
   504  
   505  	b.AssertFileContent("public/index.html", `
   506  Len cats: 2
   507  Len funny: 2
   508  Cats:|/p1/|
   509  Cats:|/p2/|
   510  Funny:|/p1/|
   511  Funny:|/p2/|`)
   512  
   513  	// Remove one category from one of the pages.
   514  	b.EditFiles("content/p1.md", `---
   515  title: Page
   516  categories: ["funny"]
   517  ---
   518  	`)
   519  
   520  	b.Build()
   521  
   522  	b.AssertFileContent("public/index.html", `
   523  Len cats: 1
   524  Len funny: 2
   525  Cats:|/p2/|
   526  Funny:|/p1/|
   527  Funny:|/p2/|`)
   528  }
   529  
   530  // https://github.com/gohugoio/hugo/issues/6590
   531  func TestTaxonomiesListPages(t *testing.T) {
   532  	b := newTestSitesBuilder(t)
   533  	b.WithTemplates("_default/list.html", `
   534  
   535  {{ template "print-taxo" "categories.cats" }}
   536  {{ template "print-taxo" "categories.funny" }}
   537  
   538  {{ define "print-taxo" }}
   539  {{ $node := index site.Taxonomies (split $ ".") }}
   540  {{ if $node }}
   541  Len {{ $ }}: {{ len $node }}
   542  {{ range $node }}
   543      {{ $ }}:|{{ .Page.RelPermalink }}|
   544  {{ end }}
   545  {{ else }}
   546  {{ $ }} not found.
   547  {{ end }}
   548  {{ end }}
   549  	`)
   550  
   551  	b.WithContent("_index.md", `---
   552  title: Home
   553  categories: ["funny", "cats"]
   554  ---
   555  	`, "blog/p1.md", `---
   556  title: Page1
   557  categories: ["funny"]
   558  ---
   559  	`, "blog/_index.md", `---
   560  title: Blog Section
   561  categories: ["cats"]
   562  ---
   563  	`,
   564  	)
   565  
   566  	b.Build(BuildCfg{})
   567  
   568  	b.AssertFileContent("public/index.html", `
   569  
   570  Len categories.cats: 2
   571  categories.cats:|/blog/|
   572  categories.cats:|/|
   573  
   574  Len categories.funny: 2
   575  categories.funny:|/|
   576  categories.funny:|/blog/p1/|
   577  `)
   578  }
   579  
   580  func TestTaxonomiesPageCollections(t *testing.T) {
   581  	t.Parallel()
   582  
   583  	b := newTestSitesBuilder(t)
   584  	b.WithContent(
   585  		"_index.md", `---
   586  title: "Home Sweet Home"
   587  categories: [ "dogs", "gorillas"]
   588  ---
   589  `,
   590  		"section/_index.md", `---
   591  title: "Section"
   592  categories: [ "cats", "dogs", "birds"]
   593  ---
   594  `,
   595  		"section/p1.md", `---
   596  title: "Page1"
   597  categories: ["funny", "cats"]
   598  ---
   599  `, "section/p2.md", `---
   600  title: "Page2"
   601  categories: ["funny"]
   602  ---
   603  `)
   604  
   605  	b.WithTemplatesAdded("index.html", `
   606  {{ $home := site.Home }}
   607  {{ $section := site.GetPage "section" }}
   608  {{ $categories := site.GetPage "categories" }}
   609  {{ $funny := site.GetPage "categories/funny" }}
   610  {{ $cats := site.GetPage "categories/cats" }}
   611  {{ $p1 := site.GetPage "section/p1" }}
   612  
   613  Categories Pages: {{ range $categories.Pages}}{{.RelPermalink }}|{{ end }}:END
   614  Funny Pages: {{ range $funny.Pages}}{{.RelPermalink }}|{{ end }}:END
   615  Cats Pages: {{ range $cats.Pages}}{{.RelPermalink }}|{{ end }}:END
   616  P1 Terms: {{ range $p1.GetTerms "categories" }}{{.RelPermalink }}|{{ end }}:END
   617  Section Terms: {{ range $section.GetTerms "categories" }}{{.RelPermalink }}|{{ end }}:END
   618  Home Terms: {{ range $home.GetTerms "categories" }}{{.RelPermalink }}|{{ end }}:END
   619  Category Paginator {{ range $categories.Paginator.Pages }}{{ .RelPermalink }}|{{ end }}:END
   620  Cats Paginator {{ range $cats.Paginator.Pages }}{{ .RelPermalink }}|{{ end }}:END
   621  
   622  `)
   623  	b.WithTemplatesAdded("404.html", `
   624  404 Terms: {{ range .GetTerms "categories" }}{{.RelPermalink }}|{{ end }}:END
   625  	`)
   626  	b.Build(BuildCfg{})
   627  
   628  	cat := b.GetPage("categories")
   629  	funny := b.GetPage("categories/funny")
   630  
   631  	b.Assert(cat, qt.Not(qt.IsNil))
   632  	b.Assert(funny, qt.Not(qt.IsNil))
   633  
   634  	b.Assert(cat.Parent().IsHome(), qt.Equals, true)
   635  	b.Assert(funny.Kind(), qt.Equals, "term")
   636  	b.Assert(funny.Parent(), qt.Equals, cat)
   637  
   638  	b.AssertFileContent("public/index.html", `
   639  Categories Pages: /categories/birds/|/categories/cats/|/categories/dogs/|/categories/funny/|/categories/gorillas/|:END
   640  Funny Pages: /section/p1/|/section/p2/|:END
   641  Cats Pages: /section/p1/|/section/|:END
   642  P1 Terms: /categories/funny/|/categories/cats/|:END
   643  Section Terms: /categories/cats/|/categories/dogs/|/categories/birds/|:END
   644  Home Terms: /categories/dogs/|/categories/gorillas/|:END
   645  Cats Paginator /section/p1/|/section/|:END
   646  Category Paginator /categories/birds/|/categories/cats/|/categories/dogs/|/categories/funny/|/categories/gorillas/|:END`,
   647  	)
   648  	b.AssertFileContent("public/404.html", "\n404 Terms: :END\n\t")
   649  	b.AssertFileContent("public/categories/funny/index.xml", `<link>http://example.com/section/p1/</link>`)
   650  	b.AssertFileContent("public/categories/index.xml", `<link>http://example.com/categories/funny/</link>`)
   651  }
   652  
   653  func TestTaxonomiesDirectoryOverlaps(t *testing.T) {
   654  	t.Parallel()
   655  
   656  	b := newTestSitesBuilder(t).WithContent(
   657  		"abc/_index.md", "---\ntitle: \"abc\"\nabcdefgs: [abc]\n---",
   658  		"abc/p1.md", "---\ntitle: \"abc-p\"\n---",
   659  		"abcdefgh/_index.md", "---\ntitle: \"abcdefgh\"\n---",
   660  		"abcdefgh/p1.md", "---\ntitle: \"abcdefgh-p\"\n---",
   661  		"abcdefghijk/index.md", "---\ntitle: \"abcdefghijk\"\n---",
   662  	)
   663  
   664  	b.WithConfigFile("toml", `
   665  baseURL = "https://example.org"
   666  titleCaseStyle = "none"
   667  
   668  [taxonomies]
   669    abcdef = "abcdefs"
   670    abcdefg = "abcdefgs"
   671    abcdefghi = "abcdefghis"
   672  `)
   673  
   674  	b.WithTemplatesAdded("index.html", `
   675  {{ range site.Pages }}Page: {{ template "print-page" . }}
   676  {{ end }}
   677  {{ $abc := site.GetPage "abcdefgs/abc" }}
   678  {{ $abcdefgs := site.GetPage "abcdefgs" }}
   679  abc: {{ template "print-page" $abc }}|IsAncestor: {{ $abc.IsAncestor $abcdefgs }}|IsDescendant: {{ $abc.IsDescendant $abcdefgs }}
   680  abcdefgs: {{ template "print-page" $abcdefgs }}|IsAncestor: {{ $abcdefgs.IsAncestor $abc }}|IsDescendant: {{ $abcdefgs.IsDescendant $abc }}
   681  
   682  {{ define "print-page" }}{{ .RelPermalink }}|{{ .Title }}|{{.Kind }}|Parent: {{ with .Parent }}{{ .RelPermalink }}{{ end }}|CurrentSection: {{ .CurrentSection.RelPermalink}}|FirstSection: {{ .FirstSection.RelPermalink }}{{ end }}
   683  
   684  `)
   685  
   686  	b.Build(BuildCfg{})
   687  
   688  	b.AssertFileContent("public/index.html", `
   689      Page: /||home|Parent: |CurrentSection: /|
   690      Page: /abc/|abc|section|Parent: /|CurrentSection: /abc/|
   691      Page: /abc/p1/|abc-p|page|Parent: /abc/|CurrentSection: /abc/|
   692      Page: /abcdefgh/|abcdefgh|section|Parent: /|CurrentSection: /abcdefgh/|
   693      Page: /abcdefgh/p1/|abcdefgh-p|page|Parent: /abcdefgh/|CurrentSection: /abcdefgh/|
   694      Page: /abcdefghijk/|abcdefghijk|page|Parent: /|CurrentSection: /|
   695      Page: /abcdefghis/|abcdefghis|taxonomy|Parent: /|CurrentSection: /abcdefghis/|
   696      Page: /abcdefgs/|abcdefgs|taxonomy|Parent: /|CurrentSection: /abcdefgs/|
   697      Page: /abcdefs/|abcdefs|taxonomy|Parent: /|CurrentSection: /abcdefs/|
   698      abc: /abcdefgs/abc/|abc|term|Parent: /abcdefgs/|CurrentSection: /abcdefgs/abc/|
   699      abcdefgs: /abcdefgs/|abcdefgs|taxonomy|Parent: /|CurrentSection: /abcdefgs/|
   700      abc: /abcdefgs/abc/|abc|term|Parent: /abcdefgs/|CurrentSection: /abcdefgs/abc/|FirstSection: /abcdefgs/|IsAncestor: false|IsDescendant: true
   701      abcdefgs: /abcdefgs/|abcdefgs|taxonomy|Parent: /|CurrentSection: /abcdefgs/|FirstSection: /abcdefgs/|IsAncestor: true|IsDescendant: false
   702  `)
   703  }
   704  
   705  func TestTaxonomiesWeightSort(t *testing.T) {
   706  	files := `
   707  -- layouts/index.html --
   708  {{ $a := site.GetPage "tags/a"}}
   709  :{{ range $a.Pages }}{{ .RelPermalink }}|{{ end }}:
   710  -- content/p1.md --
   711  ---
   712  title: P1
   713  weight: 100
   714  tags: ['a']
   715  tags_weight: 20
   716  ---
   717  -- content/p3.md --
   718  ---
   719  title: P2
   720  weight: 200
   721  tags: ['a']
   722  tags_weight: 30
   723  ---
   724  -- content/p2.md --
   725  ---
   726  title: P3
   727  weight: 50
   728  tags: ['a']
   729  tags_weight: 40
   730  ---
   731  	`
   732  
   733  	b := Test(t, files)
   734  
   735  	b.AssertFileContent("public/index.html", `:/p1/|/p3/|/p2/|:`)
   736  }
   737  
   738  func TestTaxonomiesEmptyTagsString(t *testing.T) {
   739  	t.Parallel()
   740  
   741  	files := `
   742  -- hugo.toml --
   743  [taxonomies]
   744  tag = 'tags'
   745  -- content/p1.md --
   746  +++
   747  title = "P1"
   748  tags = ''
   749  +++
   750  -- layouts/_default/single.html --
   751  Single.
   752  
   753  `
   754  	Test(t, files)
   755  }
   756  
   757  func TestTaxonomiesSpaceInName(t *testing.T) {
   758  	t.Parallel()
   759  
   760  	files := `
   761  -- hugo.toml --
   762  [taxonomies]
   763  authors = 'book authors'
   764  -- content/p1.md --
   765  ---
   766  title: Good Omens
   767  book authors:
   768    - Neil Gaiman
   769    - Terry Pratchett
   770  ---
   771  -- layouts/index.html --
   772  {{- $taxonomy := "book authors" }}
   773  Len Book Authors: {{ len (index .Site.Taxonomies $taxonomy) }}
   774  `
   775  	b := Test(t, files)
   776  
   777  	b.AssertFileContent("public/index.html", "Len Book Authors: 2")
   778  }
   779  
   780  func TestTaxonomiesListTermsHome(t *testing.T) {
   781  	files := `
   782  -- hugo.toml --
   783  baseURL = "https://example.com"
   784  [taxonomies]
   785  tag = "tags"
   786  -- content/_index.md --
   787  ---
   788  title: "Home"
   789  tags: ["a", "b", "c", "hello world"]
   790  ---
   791  -- content/tags/a/_index.md --
   792  ---
   793  title: "A"
   794  ---
   795  -- content/tags/b/_index.md --
   796  ---
   797  title: "B"
   798  ---
   799  -- content/tags/c/_index.md --
   800  ---
   801  title: "C"
   802  ---
   803  -- content/tags/d/_index.md --
   804  ---
   805  title: "D"
   806  ---
   807  -- content/tags/hello-world/_index.md --
   808  ---
   809  title: "Hello World!"
   810  ---
   811  -- layouts/home.html --
   812  Terms: {{ range site.Taxonomies.tags }}{{ .Page.Title }}: {{ .Count }}|{{ end }}$
   813  `
   814  	b := Test(t, files)
   815  
   816  	b.AssertFileContent("public/index.html", "Terms: A: 1|B: 1|C: 1|Hello World!: 1|$")
   817  }
   818  
   819  func TestTaxonomiesTermTitleAndTerm(t *testing.T) {
   820  	files := `
   821  -- hugo.toml --
   822  baseURL = "https://example.com"
   823  [taxonomies]
   824  tag = "tags"
   825  -- content/_index.md --
   826  ---
   827  title: "Home"
   828  tags: ["hellO world"]
   829  ---
   830  -- layouts/_default/term.html --
   831  {{ .Title }}|{{ .Kind }}|{{ .Data.Singular }}|{{ .Data.Plural }}|{{ .Page.Data.Term }}|
   832  `
   833  
   834  	b := Test(t, files)
   835  
   836  	b.AssertFileContent("public/tags/hello-world/index.html", "HellO World|term|tag|tags|hellO world|")
   837  }
   838  
   839  func TestTermDraft(t *testing.T) {
   840  	t.Parallel()
   841  
   842  	files := `
   843  -- layouts/_default/list.html --
   844  |{{ .Title }}|
   845  -- content/p1.md --
   846  ---
   847  title: p1
   848  tags: [a]
   849  ---
   850  -- content/tags/a/_index.md --
   851  ---
   852  title: tag-a-title-override
   853  draft: true
   854  ---
   855    `
   856  
   857  	b := Test(t, files)
   858  
   859  	b.AssertFileExists("public/tags/a/index.html", false)
   860  }
   861  
   862  func TestTermBuildNeverRenderNorList(t *testing.T) {
   863  	t.Parallel()
   864  
   865  	files := `
   866  -- layouts/index.html --
   867  |{{ len site.Taxonomies.tags }}|
   868  -- content/p1.md --
   869  ---
   870  title: p1
   871  tags: [a]
   872  ---
   873  -- content/tags/a/_index.md --
   874  ---
   875  title: tag-a-title-override
   876  build:
   877    render: never
   878    list: never
   879  ---
   880  
   881    `
   882  
   883  	b := Test(t, files)
   884  
   885  	b.AssertFileExists("public/tags/a/index.html", false)
   886  	b.AssertFileContent("public/index.html", "|0|")
   887  }
   888  
   889  func TestTaxonomiesTermLookup(t *testing.T) {
   890  	t.Parallel()
   891  
   892  	files := `
   893  -- hugo.toml --
   894  baseURL = "https://example.com"
   895  [taxonomies]
   896  tag = "tags"
   897  -- content/_index.md --
   898  ---
   899  title: "Home"
   900  tags: ["a", "b"]
   901  ---
   902  -- layouts/taxonomy/tag.html --
   903  Tag: {{ .Title }}|
   904  -- content/tags/a/_index.md --
   905  ---
   906  title: tag-a-title-override
   907  ---
   908  `
   909  
   910  	b := Test(t, files)
   911  
   912  	b.AssertFileContent("public/tags/a/index.html", "Tag: tag-a-title-override|")
   913  }
   914  
   915  func TestTaxonomyLookupIssue12193(t *testing.T) {
   916  	t.Parallel()
   917  
   918  	files := `
   919  -- hugo.toml --
   920  disableKinds = ['page','rss','section','sitemap']
   921  [taxonomies]
   922  author = 'authors'
   923  -- layouts/_default/list.html --
   924  {{ .Title }}|
   925  -- layouts/_default/author.terms.html --
   926  layouts/_default/author.terms.html
   927  -- content/authors/_index.md --
   928  ---
   929  title: Authors Page
   930  ---
   931  `
   932  
   933  	b := Test(t, files)
   934  
   935  	b.AssertFileExists("public/index.html", true)
   936  	b.AssertFileExists("public/authors/index.html", true)
   937  	b.AssertFileContent("public/authors/index.html", "layouts/_default/author.terms.html") // failing test
   938  }
   939  
   940  func TestTaxonomyNestedEmptySectionsIssue12188(t *testing.T) {
   941  	t.Parallel()
   942  
   943  	files := `
   944  -- hugo.toml --
   945  disableKinds = ['rss','sitemap']
   946  defaultContentLanguage = 'en'
   947  defaultContentLanguageInSubdir = true
   948  [languages.en]
   949  weight = 1
   950  [languages.ja]
   951  weight = 2
   952  [taxonomies]
   953  's1/category' = 's1/category'
   954  -- layouts/_default/single.html --
   955  {{ .Title }}|
   956  -- layouts/_default/list.html --
   957  {{ .Title }}|
   958  -- content/s1/p1.en.md --
   959  ---
   960  title: p1
   961  ---
   962  `
   963  
   964  	b := Test(t, files)
   965  
   966  	b.AssertFileExists("public/en/s1/index.html", true)
   967  	b.AssertFileExists("public/en/s1/p1/index.html", true)
   968  	b.AssertFileExists("public/en/s1/category/index.html", true)
   969  
   970  	b.AssertFileExists("public/ja/s1/index.html", false) // failing test
   971  	b.AssertFileExists("public/ja/s1/category/index.html", true)
   972  }