github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/hugolib/site_sections_test.go (about)

     1  // Copyright 2017-present 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  	"github.com/gohugoio/hugo/deps"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestNestedSections(t *testing.T) {
    27  	t.Parallel()
    28  
    29  	var (
    30  		assert  = require.New(t)
    31  		cfg, fs = newTestCfg()
    32  		th      = testHelper{cfg, fs, t}
    33  	)
    34  
    35  	cfg.Set("permalinks", map[string]string{
    36  		"perm a": ":sections/:title",
    37  	})
    38  
    39  	pageTemplate := `---
    40  title: T%d_%d
    41  ---
    42  Content
    43  `
    44  
    45  	// Home page
    46  	writeSource(t, fs, filepath.Join("content", "_index.md"), fmt.Sprintf(pageTemplate, -1, -1))
    47  
    48  	// Top level content page
    49  	writeSource(t, fs, filepath.Join("content", "mypage.md"), fmt.Sprintf(pageTemplate, 1234, 5))
    50  
    51  	// Top level section without index content page
    52  	writeSource(t, fs, filepath.Join("content", "top", "mypage2.md"), fmt.Sprintf(pageTemplate, 12345, 6))
    53  	// Just a page in a subfolder, i.e. not a section.
    54  	writeSource(t, fs, filepath.Join("content", "top", "folder", "mypage3.md"), fmt.Sprintf(pageTemplate, 12345, 67))
    55  
    56  	for level1 := 1; level1 < 3; level1++ {
    57  		writeSource(t, fs, filepath.Join("content", "l1", fmt.Sprintf("page_1_%d.md", level1)),
    58  			fmt.Sprintf(pageTemplate, 1, level1))
    59  	}
    60  
    61  	// Issue #3586
    62  	writeSource(t, fs, filepath.Join("content", "post", "0000.md"), fmt.Sprintf(pageTemplate, 1, 2))
    63  	writeSource(t, fs, filepath.Join("content", "post", "0000", "0001.md"), fmt.Sprintf(pageTemplate, 1, 3))
    64  	writeSource(t, fs, filepath.Join("content", "elsewhere", "0003.md"), fmt.Sprintf(pageTemplate, 1, 4))
    65  
    66  	// Empty nested section, i.e. no regular content pages.
    67  	writeSource(t, fs, filepath.Join("content", "empty1", "b", "c", "_index.md"), fmt.Sprintf(pageTemplate, 33, -1))
    68  	// Index content file a the end and in the middle.
    69  	writeSource(t, fs, filepath.Join("content", "empty2", "b", "_index.md"), fmt.Sprintf(pageTemplate, 40, -1))
    70  	writeSource(t, fs, filepath.Join("content", "empty2", "b", "c", "d", "_index.md"), fmt.Sprintf(pageTemplate, 41, -1))
    71  
    72  	// Empty with content file in the middle.
    73  	writeSource(t, fs, filepath.Join("content", "empty3", "b", "c", "d", "_index.md"), fmt.Sprintf(pageTemplate, 41, -1))
    74  	writeSource(t, fs, filepath.Join("content", "empty3", "b", "empty3.md"), fmt.Sprintf(pageTemplate, 3, -1))
    75  
    76  	// Section with permalink config
    77  	writeSource(t, fs, filepath.Join("content", "perm a", "link", "_index.md"), fmt.Sprintf(pageTemplate, 9, -1))
    78  	for i := 1; i < 4; i++ {
    79  		writeSource(t, fs, filepath.Join("content", "perm a", "link", fmt.Sprintf("page_%d.md", i)),
    80  			fmt.Sprintf(pageTemplate, 1, i))
    81  	}
    82  	writeSource(t, fs, filepath.Join("content", "perm a", "link", "regular", fmt.Sprintf("page_%d.md", 5)),
    83  		fmt.Sprintf(pageTemplate, 1, 5))
    84  
    85  	writeSource(t, fs, filepath.Join("content", "l1", "l2", "_index.md"), fmt.Sprintf(pageTemplate, 2, -1))
    86  	writeSource(t, fs, filepath.Join("content", "l1", "l2_2", "_index.md"), fmt.Sprintf(pageTemplate, 22, -1))
    87  	writeSource(t, fs, filepath.Join("content", "l1", "l2", "l3", "_index.md"), fmt.Sprintf(pageTemplate, 3, -1))
    88  
    89  	for level2 := 1; level2 < 4; level2++ {
    90  		writeSource(t, fs, filepath.Join("content", "l1", "l2", fmt.Sprintf("page_2_%d.md", level2)),
    91  			fmt.Sprintf(pageTemplate, 2, level2))
    92  	}
    93  	for level2 := 1; level2 < 3; level2++ {
    94  		writeSource(t, fs, filepath.Join("content", "l1", "l2_2", fmt.Sprintf("page_2_2_%d.md", level2)),
    95  			fmt.Sprintf(pageTemplate, 2, level2))
    96  	}
    97  	for level3 := 1; level3 < 3; level3++ {
    98  		writeSource(t, fs, filepath.Join("content", "l1", "l2", "l3", fmt.Sprintf("page_3_%d.md", level3)),
    99  			fmt.Sprintf(pageTemplate, 3, level3))
   100  	}
   101  
   102  	writeSource(t, fs, filepath.Join("content", "Spaces in Section", "page100.md"), fmt.Sprintf(pageTemplate, 10, 0))
   103  
   104  	writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), "<html>Single|{{ .Title }}</html>")
   105  	writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"),
   106  		`
   107  {{ $sect := (.Site.GetPage "section" "l1" "l2") }}
   108  <html>List|{{ .Title }}|L1/l2-IsActive: {{ .InSection $sect }}
   109  {{ range .Paginator.Pages }}
   110  PAG|{{ .Title }}|{{ $sect.InSection . }}
   111  {{ end }}
   112  </html>`)
   113  
   114  	cfg.Set("paginate", 2)
   115  
   116  	s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
   117  
   118  	require.Len(t, s.RegularPages, 21)
   119  
   120  	tests := []struct {
   121  		sections string
   122  		verify   func(p *Page)
   123  	}{
   124  		{"elsewhere", func(p *Page) {
   125  			assert.Len(p.Pages, 1)
   126  			for _, p := range p.Pages {
   127  				assert.Equal([]string{"elsewhere"}, p.sections)
   128  			}
   129  		}},
   130  		{"post", func(p *Page) {
   131  			assert.Len(p.Pages, 2)
   132  			for _, p := range p.Pages {
   133  				assert.Equal("post", p.Section())
   134  			}
   135  		}},
   136  		{"empty1", func(p *Page) {
   137  			// > b,c
   138  			assert.NotNil(p.s.getPage(KindSection, "empty1", "b"))
   139  			assert.NotNil(p.s.getPage(KindSection, "empty1", "b", "c"))
   140  
   141  		}},
   142  		{"empty2", func(p *Page) {
   143  			// > b,c,d where b and d have content files.
   144  			b := p.s.getPage(KindSection, "empty2", "b")
   145  			assert.NotNil(b)
   146  			assert.Equal("T40_-1", b.title)
   147  			c := p.s.getPage(KindSection, "empty2", "b", "c")
   148  			assert.NotNil(c)
   149  			assert.Equal("Cs", c.title)
   150  			d := p.s.getPage(KindSection, "empty2", "b", "c", "d")
   151  			assert.NotNil(d)
   152  			assert.Equal("T41_-1", d.title)
   153  
   154  			assert.False(c.Eq(d))
   155  			assert.True(c.Eq(c))
   156  			assert.False(c.Eq("asdf"))
   157  
   158  		}},
   159  		{"empty3", func(p *Page) {
   160  			// b,c,d with regular page in b
   161  			b := p.s.getPage(KindSection, "empty3", "b")
   162  			assert.NotNil(b)
   163  			assert.Len(b.Pages, 1)
   164  			assert.Equal("empty3.md", b.Pages[0].File.LogicalName())
   165  
   166  		}},
   167  		{"top", func(p *Page) {
   168  			assert.Equal("Tops", p.title)
   169  			assert.Len(p.Pages, 2)
   170  			assert.Equal("mypage2.md", p.Pages[0].LogicalName())
   171  			assert.Equal("mypage3.md", p.Pages[1].LogicalName())
   172  			home := p.Parent()
   173  			assert.True(home.IsHome())
   174  			assert.Len(p.Sections(), 0)
   175  			assert.Equal(home, home.CurrentSection())
   176  			active, err := home.InSection(home)
   177  			assert.NoError(err)
   178  			assert.True(active)
   179  		}},
   180  		{"l1", func(p *Page) {
   181  			assert.Equal("L1s", p.title)
   182  			assert.Len(p.Pages, 2)
   183  			assert.True(p.Parent().IsHome())
   184  			assert.Len(p.Sections(), 2)
   185  		}},
   186  		{"l1,l2", func(p *Page) {
   187  			assert.Equal("T2_-1", p.title)
   188  			assert.Len(p.Pages, 3)
   189  			assert.Equal(p, p.Pages[0].Parent())
   190  			assert.Equal("L1s", p.Parent().title)
   191  			assert.Equal("/l1/l2/", p.URLPath.URL)
   192  			assert.Equal("/l1/l2/", p.RelPermalink())
   193  			assert.Len(p.Sections(), 1)
   194  
   195  			for _, child := range p.Pages {
   196  				assert.Equal(p, child.CurrentSection())
   197  				active, err := child.InSection(p)
   198  				assert.NoError(err)
   199  				assert.True(active)
   200  				active, err = p.InSection(child)
   201  				assert.NoError(err)
   202  				assert.True(active)
   203  				active, err = p.InSection(p.s.getPage(KindHome))
   204  				assert.NoError(err)
   205  				assert.False(active)
   206  
   207  				isAncestor, err := p.IsAncestor(child)
   208  				assert.NoError(err)
   209  				assert.True(isAncestor)
   210  				isAncestor, err = child.IsAncestor(p)
   211  				assert.NoError(err)
   212  				assert.False(isAncestor)
   213  
   214  				isDescendant, err := p.IsDescendant(child)
   215  				assert.NoError(err)
   216  				assert.False(isDescendant)
   217  				isDescendant, err = child.IsDescendant(p)
   218  				assert.NoError(err)
   219  				assert.True(isDescendant)
   220  			}
   221  
   222  			assert.Equal(p, p.CurrentSection())
   223  
   224  		}},
   225  		{"l1,l2_2", func(p *Page) {
   226  			assert.Equal("T22_-1", p.title)
   227  			assert.Len(p.Pages, 2)
   228  			assert.Equal(filepath.FromSlash("l1/l2_2/page_2_2_1.md"), p.Pages[0].Path())
   229  			assert.Equal("L1s", p.Parent().title)
   230  			assert.Len(p.Sections(), 0)
   231  		}},
   232  		{"l1,l2,l3", func(p *Page) {
   233  			assert.Equal("T3_-1", p.title)
   234  			assert.Len(p.Pages, 2)
   235  			assert.Equal("T2_-1", p.Parent().title)
   236  			assert.Len(p.Sections(), 0)
   237  
   238  			l1 := p.s.getPage(KindSection, "l1")
   239  			isDescendant, err := l1.IsDescendant(p)
   240  			assert.NoError(err)
   241  			assert.False(isDescendant)
   242  			isDescendant, err = p.IsDescendant(l1)
   243  			assert.NoError(err)
   244  			assert.True(isDescendant)
   245  
   246  			isAncestor, err := l1.IsAncestor(p)
   247  			assert.NoError(err)
   248  			assert.True(isAncestor)
   249  			isAncestor, err = p.IsAncestor(l1)
   250  			assert.NoError(err)
   251  			assert.False(isAncestor)
   252  
   253  		}},
   254  		{"perm a,link", func(p *Page) {
   255  			assert.Equal("T9_-1", p.title)
   256  			assert.Equal("/perm-a/link/", p.RelPermalink())
   257  			assert.Len(p.Pages, 4)
   258  			first := p.Pages[0]
   259  			assert.Equal("/perm-a/link/t1_1/", first.RelPermalink())
   260  			th.assertFileContent("public/perm-a/link/t1_1/index.html", "Single|T1_1")
   261  
   262  			last := p.Pages[3]
   263  			assert.Equal("/perm-a/link/t1_5/", last.RelPermalink())
   264  
   265  		}},
   266  	}
   267  
   268  	home := s.getPage(KindHome)
   269  
   270  	for _, test := range tests {
   271  		sections := strings.Split(test.sections, ",")
   272  		p := s.getPage(KindSection, sections...)
   273  		assert.NotNil(p, fmt.Sprint(sections))
   274  
   275  		if p.Pages != nil {
   276  			assert.Equal(p.Pages, p.Data["Pages"])
   277  		}
   278  		assert.NotNil(p.Parent(), fmt.Sprintf("Parent nil: %q", test.sections))
   279  		test.verify(p)
   280  	}
   281  
   282  	assert.NotNil(home)
   283  
   284  	assert.Len(home.Sections(), 9)
   285  	assert.Equal(home.Sections(), s.Info.Sections())
   286  
   287  	rootPage := s.getPage(KindPage, "mypage.md")
   288  	assert.NotNil(rootPage)
   289  	assert.True(rootPage.Parent().IsHome())
   290  
   291  	// Add a odd test for this as this looks a little bit off, but I'm not in the mood
   292  	// to think too hard a out this right now. It works, but people will have to spell
   293  	// out the directory name as is.
   294  	// If we later decide to do something about this, we will have to do some normalization in
   295  	// getPage.
   296  	// TODO(bep)
   297  	sectionWithSpace := s.getPage(KindSection, "Spaces in Section")
   298  	require.NotNil(t, sectionWithSpace)
   299  	require.Equal(t, "/spaces-in-section/", sectionWithSpace.RelPermalink())
   300  
   301  	th.assertFileContent("public/l1/l2/page/2/index.html", "L1/l2-IsActive: true", "PAG|T2_3|true")
   302  
   303  }