github.com/kristoff-it/hugo@v0.47.1/hugolib/pagination_test.go (about)

     1  // Copyright 2015 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  	"html/template"
    19  	"path/filepath"
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/gohugoio/hugo/deps"
    24  	"github.com/gohugoio/hugo/output"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func TestSplitPages(t *testing.T) {
    29  	t.Parallel()
    30  	s := newTestSite(t)
    31  
    32  	pages := createTestPages(s, 21)
    33  	chunks := splitPages(pages, 5)
    34  	require.Equal(t, 5, len(chunks))
    35  
    36  	for i := 0; i < 4; i++ {
    37  		require.Equal(t, 5, chunks[i].Len())
    38  	}
    39  
    40  	lastChunk := chunks[4]
    41  	require.Equal(t, 1, lastChunk.Len())
    42  
    43  }
    44  
    45  func TestSplitPageGroups(t *testing.T) {
    46  	t.Parallel()
    47  	s := newTestSite(t)
    48  	pages := createTestPages(s, 21)
    49  	groups, _ := pages.GroupBy("Weight", "desc")
    50  	chunks := splitPageGroups(groups, 5)
    51  	require.Equal(t, 5, len(chunks))
    52  
    53  	firstChunk := chunks[0]
    54  
    55  	// alternate weight 5 and 10
    56  	if groups, ok := firstChunk.(PagesGroup); ok {
    57  		require.Equal(t, 5, groups.Len())
    58  		for _, pg := range groups {
    59  			// first group 10 in weight
    60  			require.Equal(t, 10, pg.Key)
    61  			for _, p := range pg.Pages {
    62  				require.True(t, p.fuzzyWordCount%2 == 0) // magic test
    63  			}
    64  		}
    65  	} else {
    66  		t.Fatal("Excepted PageGroup")
    67  	}
    68  
    69  	lastChunk := chunks[4]
    70  
    71  	if groups, ok := lastChunk.(PagesGroup); ok {
    72  		require.Equal(t, 1, groups.Len())
    73  		for _, pg := range groups {
    74  			// last should have 5 in weight
    75  			require.Equal(t, 5, pg.Key)
    76  			for _, p := range pg.Pages {
    77  				require.True(t, p.fuzzyWordCount%2 != 0) // magic test
    78  			}
    79  		}
    80  	} else {
    81  		t.Fatal("Excepted PageGroup")
    82  	}
    83  
    84  }
    85  
    86  func TestPager(t *testing.T) {
    87  	t.Parallel()
    88  	s := newTestSite(t)
    89  	pages := createTestPages(s, 21)
    90  	groups, _ := pages.GroupBy("Weight", "desc")
    91  
    92  	urlFactory := func(page int) string {
    93  		return fmt.Sprintf("page/%d/", page)
    94  	}
    95  
    96  	_, err := newPaginatorFromPages(pages, -1, urlFactory)
    97  	require.NotNil(t, err)
    98  
    99  	_, err = newPaginatorFromPageGroups(groups, -1, urlFactory)
   100  	require.NotNil(t, err)
   101  
   102  	pag, err := newPaginatorFromPages(pages, 5, urlFactory)
   103  	require.Nil(t, err)
   104  	doTestPages(t, pag)
   105  	first := pag.Pagers()[0].First()
   106  	require.Equal(t, "Pager 1", first.String())
   107  	require.NotEmpty(t, first.Pages())
   108  	require.Empty(t, first.PageGroups())
   109  
   110  	pag, err = newPaginatorFromPageGroups(groups, 5, urlFactory)
   111  	require.Nil(t, err)
   112  	doTestPages(t, pag)
   113  	first = pag.Pagers()[0].First()
   114  	require.NotEmpty(t, first.PageGroups())
   115  	require.Empty(t, first.Pages())
   116  
   117  }
   118  
   119  func doTestPages(t *testing.T, paginator *paginator) {
   120  
   121  	paginatorPages := paginator.Pagers()
   122  
   123  	require.Equal(t, 5, len(paginatorPages))
   124  	require.Equal(t, 21, paginator.TotalNumberOfElements())
   125  	require.Equal(t, 5, paginator.PageSize())
   126  	require.Equal(t, 5, paginator.TotalPages())
   127  
   128  	first := paginatorPages[0]
   129  	require.Equal(t, template.HTML("page/1/"), first.URL())
   130  	require.Equal(t, first, first.First())
   131  	require.True(t, first.HasNext())
   132  	require.Equal(t, paginatorPages[1], first.Next())
   133  	require.False(t, first.HasPrev())
   134  	require.Nil(t, first.Prev())
   135  	require.Equal(t, 5, first.NumberOfElements())
   136  	require.Equal(t, 1, first.PageNumber())
   137  
   138  	third := paginatorPages[2]
   139  	require.True(t, third.HasNext())
   140  	require.True(t, third.HasPrev())
   141  	require.Equal(t, paginatorPages[1], third.Prev())
   142  
   143  	last := paginatorPages[4]
   144  	require.Equal(t, template.HTML("page/5/"), last.URL())
   145  	require.Equal(t, last, last.Last())
   146  	require.False(t, last.HasNext())
   147  	require.Nil(t, last.Next())
   148  	require.True(t, last.HasPrev())
   149  	require.Equal(t, 1, last.NumberOfElements())
   150  	require.Equal(t, 5, last.PageNumber())
   151  }
   152  
   153  func TestPagerNoPages(t *testing.T) {
   154  	t.Parallel()
   155  	s := newTestSite(t)
   156  	pages := createTestPages(s, 0)
   157  	groups, _ := pages.GroupBy("Weight", "desc")
   158  
   159  	urlFactory := func(page int) string {
   160  		return fmt.Sprintf("page/%d/", page)
   161  	}
   162  
   163  	paginator, _ := newPaginatorFromPages(pages, 5, urlFactory)
   164  	doTestPagerNoPages(t, paginator)
   165  
   166  	first := paginator.Pagers()[0].First()
   167  	require.Empty(t, first.PageGroups())
   168  	require.Empty(t, first.Pages())
   169  
   170  	paginator, _ = newPaginatorFromPageGroups(groups, 5, urlFactory)
   171  	doTestPagerNoPages(t, paginator)
   172  
   173  	first = paginator.Pagers()[0].First()
   174  	require.Empty(t, first.PageGroups())
   175  	require.Empty(t, first.Pages())
   176  
   177  }
   178  
   179  func doTestPagerNoPages(t *testing.T, paginator *paginator) {
   180  	paginatorPages := paginator.Pagers()
   181  
   182  	require.Equal(t, 1, len(paginatorPages))
   183  	require.Equal(t, 0, paginator.TotalNumberOfElements())
   184  	require.Equal(t, 5, paginator.PageSize())
   185  	require.Equal(t, 0, paginator.TotalPages())
   186  
   187  	// pageOne should be nothing but the first
   188  	pageOne := paginatorPages[0]
   189  	require.NotNil(t, pageOne.First())
   190  	require.False(t, pageOne.HasNext())
   191  	require.False(t, pageOne.HasPrev())
   192  	require.Nil(t, pageOne.Next())
   193  	require.Equal(t, 1, len(pageOne.Pagers()))
   194  	require.Equal(t, 0, pageOne.Pages().Len())
   195  	require.Equal(t, 0, pageOne.NumberOfElements())
   196  	require.Equal(t, 0, pageOne.TotalNumberOfElements())
   197  	require.Equal(t, 0, pageOne.TotalPages())
   198  	require.Equal(t, 1, pageOne.PageNumber())
   199  	require.Equal(t, 5, pageOne.PageSize())
   200  
   201  }
   202  
   203  func TestPaginationURLFactory(t *testing.T) {
   204  	t.Parallel()
   205  	cfg, fs := newTestCfg()
   206  	cfg.Set("paginatePath", "zoo")
   207  
   208  	for _, uglyURLs := range []bool{false, true} {
   209  		for _, canonifyURLs := range []bool{false, true} {
   210  			t.Run(fmt.Sprintf("uglyURLs=%t,canonifyURLs=%t", uglyURLs, canonifyURLs), func(t *testing.T) {
   211  
   212  				tests := []struct {
   213  					name     string
   214  					d        targetPathDescriptor
   215  					baseURL  string
   216  					page     int
   217  					expected string
   218  				}{
   219  					{"HTML home page 32",
   220  						targetPathDescriptor{Kind: KindHome, Type: output.HTMLFormat}, "http://example.com/", 32, "/zoo/32/"},
   221  					{"JSON home page 42",
   222  						targetPathDescriptor{Kind: KindHome, Type: output.JSONFormat}, "http://example.com/", 42, "/zoo/42/"},
   223  					// Issue #1252
   224  					{"BaseURL with sub path",
   225  						targetPathDescriptor{Kind: KindHome, Type: output.HTMLFormat}, "http://example.com/sub/", 999, "/sub/zoo/999/"},
   226  				}
   227  
   228  				for _, test := range tests {
   229  					d := test.d
   230  					cfg.Set("baseURL", test.baseURL)
   231  					cfg.Set("canonifyURLs", canonifyURLs)
   232  					cfg.Set("uglyURLs", uglyURLs)
   233  					d.UglyURLs = uglyURLs
   234  
   235  					expected := test.expected
   236  
   237  					if canonifyURLs {
   238  						expected = strings.Replace(expected, "/sub", "", 1)
   239  					}
   240  
   241  					if uglyURLs {
   242  						expected = expected[:len(expected)-1] + "." + test.d.Type.MediaType.Suffix()
   243  					}
   244  
   245  					pathSpec := newTestPathSpec(fs, cfg)
   246  					d.PathSpec = pathSpec
   247  
   248  					factory := newPaginationURLFactory(d)
   249  
   250  					got := factory(test.page)
   251  
   252  					require.Equal(t, expected, got)
   253  
   254  				}
   255  			})
   256  		}
   257  	}
   258  }
   259  
   260  func TestPaginator(t *testing.T) {
   261  	t.Parallel()
   262  	for _, useViper := range []bool{false, true} {
   263  		doTestPaginator(t, useViper)
   264  	}
   265  }
   266  
   267  func doTestPaginator(t *testing.T, useViper bool) {
   268  
   269  	cfg, fs := newTestCfg()
   270  
   271  	pagerSize := 5
   272  	if useViper {
   273  		cfg.Set("paginate", pagerSize)
   274  	} else {
   275  		cfg.Set("paginate", -1)
   276  	}
   277  
   278  	s, err := NewSiteForCfg(deps.DepsCfg{Cfg: cfg, Fs: fs})
   279  	require.NoError(t, err)
   280  
   281  	pages := createTestPages(s, 12)
   282  	n1, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   283  	n2, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   284  	n1.data["Pages"] = pages
   285  
   286  	var paginator1 *Pager
   287  
   288  	if useViper {
   289  		paginator1, err = n1.Paginator()
   290  	} else {
   291  		paginator1, err = n1.Paginator(pagerSize)
   292  	}
   293  
   294  	require.Nil(t, err)
   295  	require.NotNil(t, paginator1)
   296  	require.Equal(t, 3, paginator1.TotalPages())
   297  	require.Equal(t, 12, paginator1.TotalNumberOfElements())
   298  
   299  	n2.paginator = paginator1.Next()
   300  	paginator2, err := n2.Paginator()
   301  	require.Nil(t, err)
   302  	require.Equal(t, paginator2, paginator1.Next())
   303  
   304  	n1.data["Pages"] = createTestPages(s, 1)
   305  	samePaginator, _ := n1.Paginator()
   306  	require.Equal(t, paginator1, samePaginator)
   307  
   308  	pp, _ := s.NewPage("test")
   309  	p, _ := newPageOutput(pp, false, false, output.HTMLFormat)
   310  
   311  	_, err = p.Paginator()
   312  	require.NotNil(t, err)
   313  }
   314  
   315  func TestPaginatorWithNegativePaginate(t *testing.T) {
   316  	t.Parallel()
   317  	s := newTestSite(t, "paginate", -1)
   318  	n1, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   319  	_, err := n1.Paginator()
   320  	require.Error(t, err)
   321  }
   322  
   323  func TestPaginate(t *testing.T) {
   324  	t.Parallel()
   325  	for _, useViper := range []bool{false, true} {
   326  		doTestPaginate(t, useViper)
   327  	}
   328  }
   329  
   330  func TestPaginatorURL(t *testing.T) {
   331  	t.Parallel()
   332  	cfg, fs := newTestCfg()
   333  
   334  	cfg.Set("paginate", 2)
   335  	cfg.Set("paginatePath", "testing")
   336  
   337  	for i := 0; i < 10; i++ {
   338  		// Issue #2177, do not double encode URLs
   339  		writeSource(t, fs, filepath.Join("content", "阅读", fmt.Sprintf("page%d.md", (i+1))),
   340  			fmt.Sprintf(`---
   341  title: Page%d
   342  ---
   343  Conten%d
   344  `, (i+1), i+1))
   345  
   346  	}
   347  	writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), "<html><body>{{.Content}}</body></html>")
   348  	writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"),
   349  		`
   350  <html><body>
   351  Count: {{ .Paginator.TotalNumberOfElements }}
   352  Pages: {{ .Paginator.TotalPages }}
   353  {{ range .Paginator.Pagers -}}
   354   {{ .PageNumber }}: {{ .URL }} 
   355  {{ end }}
   356  </body></html>`)
   357  
   358  	s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{})
   359  
   360  	th := testHelper{s.Cfg, s.Fs, t}
   361  
   362  	th.assertFileContent(filepath.Join("public", "阅读", "testing", "2", "index.html"), "2: /%E9%98%85%E8%AF%BB/testing/2/")
   363  
   364  }
   365  
   366  func doTestPaginate(t *testing.T, useViper bool) {
   367  	pagerSize := 5
   368  
   369  	var (
   370  		s   *Site
   371  		err error
   372  	)
   373  
   374  	if useViper {
   375  		s = newTestSite(t, "paginate", pagerSize)
   376  	} else {
   377  		s = newTestSite(t, "paginate", -1)
   378  	}
   379  
   380  	pages := createTestPages(s, 6)
   381  	n1, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   382  	n2, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   383  
   384  	var paginator1, paginator2 *Pager
   385  
   386  	if useViper {
   387  		paginator1, err = n1.Paginate(pages)
   388  	} else {
   389  		paginator1, err = n1.Paginate(pages, pagerSize)
   390  	}
   391  
   392  	require.Nil(t, err)
   393  	require.NotNil(t, paginator1)
   394  	require.Equal(t, 2, paginator1.TotalPages())
   395  	require.Equal(t, 6, paginator1.TotalNumberOfElements())
   396  
   397  	n2.paginator = paginator1.Next()
   398  	if useViper {
   399  		paginator2, err = n2.Paginate(pages)
   400  	} else {
   401  		paginator2, err = n2.Paginate(pages, pagerSize)
   402  	}
   403  	require.Nil(t, err)
   404  	require.Equal(t, paginator2, paginator1.Next())
   405  
   406  	pp, err := s.NewPage("test")
   407  	p, _ := newPageOutput(pp, false, false, output.HTMLFormat)
   408  
   409  	_, err = p.Paginate(pages)
   410  	require.NotNil(t, err)
   411  }
   412  
   413  func TestInvalidOptions(t *testing.T) {
   414  	t.Parallel()
   415  	s := newTestSite(t)
   416  	n1, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   417  
   418  	_, err := n1.Paginate(createTestPages(s, 1), 1, 2)
   419  	require.NotNil(t, err)
   420  	_, err = n1.Paginator(1, 2)
   421  	require.NotNil(t, err)
   422  	_, err = n1.Paginator(-1)
   423  	require.NotNil(t, err)
   424  }
   425  
   426  func TestPaginateWithNegativePaginate(t *testing.T) {
   427  	t.Parallel()
   428  	cfg, fs := newTestCfg()
   429  	cfg.Set("paginate", -1)
   430  
   431  	s, err := NewSiteForCfg(deps.DepsCfg{Cfg: cfg, Fs: fs})
   432  	require.NoError(t, err)
   433  
   434  	n, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   435  
   436  	_, err = n.Paginate(createTestPages(s, 2))
   437  	require.NotNil(t, err)
   438  }
   439  
   440  func TestPaginatePages(t *testing.T) {
   441  	t.Parallel()
   442  	s := newTestSite(t)
   443  
   444  	groups, _ := createTestPages(s, 31).GroupBy("Weight", "desc")
   445  	pd := targetPathDescriptor{Kind: KindHome, Type: output.HTMLFormat, PathSpec: s.PathSpec, Addends: "t"}
   446  
   447  	for i, seq := range []interface{}{createTestPages(s, 11), groups, WeightedPages{}, PageGroup{}, &Pages{}} {
   448  		v, err := paginatePages(pd, seq, 11)
   449  		require.NotNil(t, v, "Val %d", i)
   450  		require.Nil(t, err, "Err %d", i)
   451  	}
   452  	_, err := paginatePages(pd, Site{}, 11)
   453  	require.NotNil(t, err)
   454  
   455  }
   456  
   457  // Issue #993
   458  func TestPaginatorFollowedByPaginateShouldFail(t *testing.T) {
   459  	t.Parallel()
   460  	s := newTestSite(t, "paginate", 10)
   461  	n1, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   462  	n2, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   463  
   464  	_, err := n1.Paginator()
   465  	require.Nil(t, err)
   466  	_, err = n1.Paginate(createTestPages(s, 2))
   467  	require.NotNil(t, err)
   468  
   469  	_, err = n2.Paginate(createTestPages(s, 2))
   470  	require.Nil(t, err)
   471  
   472  }
   473  
   474  func TestPaginateFollowedByDifferentPaginateShouldFail(t *testing.T) {
   475  	t.Parallel()
   476  	s := newTestSite(t, "paginate", 10)
   477  
   478  	n1, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   479  	n2, _ := newPageOutput(s.newHomePage(), false, false, output.HTMLFormat)
   480  
   481  	p1 := createTestPages(s, 2)
   482  	p2 := createTestPages(s, 10)
   483  
   484  	_, err := n1.Paginate(p1)
   485  	require.Nil(t, err)
   486  
   487  	_, err = n1.Paginate(p1)
   488  	require.Nil(t, err)
   489  
   490  	_, err = n1.Paginate(p2)
   491  	require.NotNil(t, err)
   492  
   493  	_, err = n2.Paginate(p2)
   494  	require.Nil(t, err)
   495  }
   496  
   497  func TestProbablyEqualPageLists(t *testing.T) {
   498  	t.Parallel()
   499  	s := newTestSite(t)
   500  	fivePages := createTestPages(s, 5)
   501  	zeroPages := createTestPages(s, 0)
   502  	zeroPagesByWeight, _ := createTestPages(s, 0).GroupBy("Weight", "asc")
   503  	fivePagesByWeight, _ := createTestPages(s, 5).GroupBy("Weight", "asc")
   504  	ninePagesByWeight, _ := createTestPages(s, 9).GroupBy("Weight", "asc")
   505  
   506  	for i, this := range []struct {
   507  		v1     interface{}
   508  		v2     interface{}
   509  		expect bool
   510  	}{
   511  		{nil, nil, true},
   512  		{"a", "b", true},
   513  		{"a", fivePages, false},
   514  		{fivePages, "a", false},
   515  		{fivePages, createTestPages(s, 2), false},
   516  		{fivePages, fivePages, true},
   517  		{zeroPages, zeroPages, true},
   518  		{fivePagesByWeight, fivePagesByWeight, true},
   519  		{zeroPagesByWeight, fivePagesByWeight, false},
   520  		{zeroPagesByWeight, zeroPagesByWeight, true},
   521  		{fivePagesByWeight, fivePages, false},
   522  		{fivePagesByWeight, ninePagesByWeight, false},
   523  	} {
   524  		result := probablyEqualPageLists(this.v1, this.v2)
   525  
   526  		if result != this.expect {
   527  			t.Errorf("[%d] got %t but expected %t", i, result, this.expect)
   528  
   529  		}
   530  	}
   531  }
   532  
   533  func TestPage(t *testing.T) {
   534  	t.Parallel()
   535  	urlFactory := func(page int) string {
   536  		return fmt.Sprintf("page/%d/", page)
   537  	}
   538  
   539  	s := newTestSite(t)
   540  
   541  	fivePages := createTestPages(s, 7)
   542  	fivePagesFuzzyWordCount, _ := createTestPages(s, 7).GroupBy("FuzzyWordCount", "asc")
   543  
   544  	p1, _ := newPaginatorFromPages(fivePages, 2, urlFactory)
   545  	p2, _ := newPaginatorFromPageGroups(fivePagesFuzzyWordCount, 2, urlFactory)
   546  
   547  	f1 := p1.pagers[0].First()
   548  	f2 := p2.pagers[0].First()
   549  
   550  	page11, _ := f1.page(1)
   551  	page1Nil, _ := f1.page(3)
   552  
   553  	page21, _ := f2.page(1)
   554  	page2Nil, _ := f2.page(3)
   555  
   556  	require.Equal(t, 3, page11.fuzzyWordCount)
   557  	require.Nil(t, page1Nil)
   558  
   559  	require.Equal(t, 3, page21.fuzzyWordCount)
   560  	require.Nil(t, page2Nil)
   561  }
   562  
   563  func createTestPages(s *Site, num int) Pages {
   564  	pages := make(Pages, num)
   565  
   566  	for i := 0; i < num; i++ {
   567  		p := s.newPage(filepath.FromSlash(fmt.Sprintf("/x/y/z/p%d.md", i)))
   568  		w := 5
   569  		if i%2 == 0 {
   570  			w = 10
   571  		}
   572  		p.fuzzyWordCount = i + 2
   573  		p.Weight = w
   574  		pages[i] = p
   575  
   576  	}
   577  
   578  	return pages
   579  }