github.com/fighterlyt/hugo@v0.47.1/hugolib/page_collections_test.go (about)

     1  // Copyright 2017 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  	"math/rand"
    19  	"path"
    20  	"path/filepath"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/gohugoio/hugo/deps"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  const pageCollectionsPageTemplate = `---
    29  title: "%s"
    30  categories:
    31  - Hugo
    32  ---
    33  # Doc
    34  `
    35  
    36  func BenchmarkGetPage(b *testing.B) {
    37  	var (
    38  		cfg, fs = newTestCfg()
    39  		r       = rand.New(rand.NewSource(time.Now().UnixNano()))
    40  	)
    41  
    42  	for i := 0; i < 10; i++ {
    43  		for j := 0; j < 100; j++ {
    44  			writeSource(b, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), fmt.Sprintf("page%d.md", j)), "CONTENT")
    45  		}
    46  	}
    47  
    48  	s := buildSingleSite(b, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{SkipRender: true})
    49  
    50  	pagePaths := make([]string, b.N)
    51  
    52  	for i := 0; i < b.N; i++ {
    53  		pagePaths[i] = fmt.Sprintf("sect%d", r.Intn(10))
    54  	}
    55  
    56  	b.ResetTimer()
    57  	for i := 0; i < b.N; i++ {
    58  		home, _ := s.getPageNew(nil, "/")
    59  		if home == nil {
    60  			b.Fatal("Home is nil")
    61  		}
    62  
    63  		p, _ := s.getPageNew(nil, pagePaths[i])
    64  		if p == nil {
    65  			b.Fatal("Section is nil")
    66  		}
    67  
    68  	}
    69  }
    70  
    71  func BenchmarkGetPageRegular(b *testing.B) {
    72  	var (
    73  		cfg, fs = newTestCfg()
    74  		r       = rand.New(rand.NewSource(time.Now().UnixNano()))
    75  	)
    76  
    77  	for i := 0; i < 10; i++ {
    78  		for j := 0; j < 100; j++ {
    79  			content := fmt.Sprintf(pageCollectionsPageTemplate, fmt.Sprintf("Title%d_%d", i, j))
    80  			writeSource(b, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), fmt.Sprintf("page%d.md", j)), content)
    81  		}
    82  	}
    83  
    84  	s := buildSingleSite(b, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{SkipRender: true})
    85  
    86  	pagePaths := make([]string, b.N)
    87  
    88  	for i := 0; i < b.N; i++ {
    89  		pagePaths[i] = path.Join(fmt.Sprintf("sect%d", r.Intn(10)), fmt.Sprintf("page%d.md", r.Intn(100)))
    90  	}
    91  
    92  	b.ResetTimer()
    93  	for i := 0; i < b.N; i++ {
    94  		page, _ := s.getPageNew(nil, pagePaths[i])
    95  		require.NotNil(b, page)
    96  	}
    97  }
    98  
    99  type testCase struct {
   100  	kind          string
   101  	context       *Page
   102  	path          []string
   103  	expectedTitle string
   104  }
   105  
   106  func (t *testCase) check(p *Page, err error, errorMsg string, assert *require.Assertions) {
   107  	switch t.kind {
   108  	case "Ambiguous":
   109  		assert.Error(err)
   110  		assert.Nil(p, errorMsg)
   111  	case "NoPage":
   112  		assert.NoError(err)
   113  		assert.Nil(p, errorMsg)
   114  	default:
   115  		assert.NoError(err, errorMsg)
   116  		assert.NotNil(p, errorMsg)
   117  		assert.Equal(t.kind, p.Kind, errorMsg)
   118  		assert.Equal(t.expectedTitle, p.title, errorMsg)
   119  	}
   120  }
   121  
   122  func TestGetPage(t *testing.T) {
   123  
   124  	var (
   125  		assert  = require.New(t)
   126  		cfg, fs = newTestCfg()
   127  	)
   128  
   129  	for i := 0; i < 10; i++ {
   130  		for j := 0; j < 10; j++ {
   131  			content := fmt.Sprintf(pageCollectionsPageTemplate, fmt.Sprintf("Title%d_%d", i, j))
   132  			writeSource(t, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), fmt.Sprintf("page%d.md", j)), content)
   133  		}
   134  	}
   135  
   136  	content := fmt.Sprintf(pageCollectionsPageTemplate, "home page")
   137  	writeSource(t, fs, filepath.Join("content", "_index.md"), content)
   138  
   139  	content = fmt.Sprintf(pageCollectionsPageTemplate, "about page")
   140  	writeSource(t, fs, filepath.Join("content", "about.md"), content)
   141  
   142  	content = fmt.Sprintf(pageCollectionsPageTemplate, "section 3")
   143  	writeSource(t, fs, filepath.Join("content", "sect3", "_index.md"), content)
   144  
   145  	content = fmt.Sprintf(pageCollectionsPageTemplate, "UniqueBase")
   146  	writeSource(t, fs, filepath.Join("content", "sect3", "unique.md"), content)
   147  
   148  	content = fmt.Sprintf(pageCollectionsPageTemplate, "another sect7")
   149  	writeSource(t, fs, filepath.Join("content", "sect3", "sect7", "_index.md"), content)
   150  
   151  	content = fmt.Sprintf(pageCollectionsPageTemplate, "deep page")
   152  	writeSource(t, fs, filepath.Join("content", "sect3", "subsect", "deep.md"), content)
   153  
   154  	s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{SkipRender: true})
   155  
   156  	sec3, err := s.getPageNew(nil, "/sect3")
   157  	assert.NoError(err, "error getting Page for /sec3")
   158  	assert.NotNil(sec3, "failed to get Page for /sec3")
   159  
   160  	tests := []testCase{
   161  		// legacy content root relative paths
   162  		{KindHome, nil, []string{}, "home page"},
   163  		{KindPage, nil, []string{"about.md"}, "about page"},
   164  		{KindSection, nil, []string{"sect3"}, "section 3"},
   165  		{KindPage, nil, []string{"sect3/page1.md"}, "Title3_1"},
   166  		{KindPage, nil, []string{"sect4/page2.md"}, "Title4_2"},
   167  		{KindSection, nil, []string{"sect3/sect7"}, "another sect7"},
   168  		{KindPage, nil, []string{"sect3/subsect/deep.md"}, "deep page"},
   169  		{KindPage, nil, []string{filepath.FromSlash("sect5/page3.md")}, "Title5_3"}, //test OS-specific path
   170  
   171  		// shorthand refs (potentially ambiguous)
   172  		{KindPage, nil, []string{"unique.md"}, "UniqueBase"},
   173  		{"Ambiguous", nil, []string{"page1.md"}, ""},
   174  
   175  		// ISSUE: This is an ambiguous ref, but because we have to support the legacy
   176  		// content root relative paths without a leading slash, the lookup
   177  		// returns /sect7. This undermines ambiguity detection, but we have no choice.
   178  		//{"Ambiguous", nil, []string{"sect7"}, ""},
   179  		{KindSection, nil, []string{"sect7"}, "Sect7s"},
   180  
   181  		// absolute paths
   182  		{KindHome, nil, []string{"/"}, "home page"},
   183  		{KindPage, nil, []string{"/about.md"}, "about page"},
   184  		{KindSection, nil, []string{"/sect3"}, "section 3"},
   185  		{KindPage, nil, []string{"/sect3/page1.md"}, "Title3_1"},
   186  		{KindPage, nil, []string{"/sect4/page2.md"}, "Title4_2"},
   187  		{KindSection, nil, []string{"/sect3/sect7"}, "another sect7"},
   188  		{KindPage, nil, []string{"/sect3/subsect/deep.md"}, "deep page"},
   189  		{KindPage, nil, []string{filepath.FromSlash("/sect5/page3.md")}, "Title5_3"}, //test OS-specific path
   190  		{KindPage, nil, []string{"/sect3/unique.md"}, "UniqueBase"},                  //next test depends on this page existing
   191  		// {"NoPage", nil, []string{"/unique.md"}, ""},  // ISSUE #4969: this is resolving to /sect3/unique.md
   192  		{"NoPage", nil, []string{"/missing-page.md"}, ""},
   193  		{"NoPage", nil, []string{"/missing-section"}, ""},
   194  
   195  		// relative paths
   196  		{KindHome, sec3, []string{".."}, "home page"},
   197  		{KindHome, sec3, []string{"../"}, "home page"},
   198  		{KindPage, sec3, []string{"../about.md"}, "about page"},
   199  		{KindSection, sec3, []string{"."}, "section 3"},
   200  		{KindSection, sec3, []string{"./"}, "section 3"},
   201  		{KindPage, sec3, []string{"page1.md"}, "Title3_1"},
   202  		{KindPage, sec3, []string{"./page1.md"}, "Title3_1"},
   203  		{KindPage, sec3, []string{"../sect4/page2.md"}, "Title4_2"},
   204  		{KindSection, sec3, []string{"sect7"}, "another sect7"},
   205  		{KindSection, sec3, []string{"./sect7"}, "another sect7"},
   206  		{KindPage, sec3, []string{"./subsect/deep.md"}, "deep page"},
   207  		{KindPage, sec3, []string{"./subsect/../../sect7/page9.md"}, "Title7_9"},
   208  		{KindPage, sec3, []string{filepath.FromSlash("../sect5/page3.md")}, "Title5_3"}, //test OS-specific path
   209  		{KindPage, sec3, []string{"./unique.md"}, "UniqueBase"},
   210  		{"NoPage", sec3, []string{"./sect2"}, ""},
   211  		//{"NoPage", sec3, []string{"sect2"}, ""}, // ISSUE: /sect3 page relative query is resolving to /sect2
   212  
   213  		// absolute paths ignore context
   214  		{KindHome, sec3, []string{"/"}, "home page"},
   215  		{KindPage, sec3, []string{"/about.md"}, "about page"},
   216  		{KindPage, sec3, []string{"/sect4/page2.md"}, "Title4_2"},
   217  		{KindPage, sec3, []string{"/sect3/subsect/deep.md"}, "deep page"}, //next test depends on this page existing
   218  		{"NoPage", sec3, []string{"/subsect/deep.md"}, ""},
   219  	}
   220  
   221  	for _, test := range tests {
   222  		errorMsg := fmt.Sprintf("Test case %s %v -> %s", test.context, test.path, test.expectedTitle)
   223  
   224  		// test legacy public Site.GetPage (which does not support page context relative queries)
   225  		if test.context == nil {
   226  			args := append([]string{test.kind}, test.path...)
   227  			page, err := s.Info.GetPage(args...)
   228  			test.check(page, err, errorMsg, assert)
   229  		}
   230  
   231  		// test new internal Site.getPageNew
   232  		var ref string
   233  		if len(test.path) == 1 {
   234  			ref = filepath.ToSlash(test.path[0])
   235  		} else {
   236  			ref = path.Join(test.path...)
   237  		}
   238  		page2, err := s.getPageNew(test.context, ref)
   239  		test.check(page2, err, errorMsg, assert)
   240  	}
   241  
   242  }