hugo

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

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

content_test.go (16211B)

    1 // Copyright 2016 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 create_test
   15 
   16 import (
   17 	"fmt"
   18 	"os"
   19 	"path/filepath"
   20 	"strings"
   21 	"testing"
   22 
   23 	"github.com/gohugoio/hugo/config"
   24 
   25 	"github.com/gohugoio/hugo/deps"
   26 
   27 	"github.com/gohugoio/hugo/hugolib"
   28 
   29 	"github.com/gohugoio/hugo/hugofs"
   30 
   31 	qt "github.com/frankban/quicktest"
   32 	"github.com/gohugoio/hugo/create"
   33 	"github.com/gohugoio/hugo/helpers"
   34 	"github.com/spf13/afero"
   35 )
   36 
   37 // TODO(bep) clean this up. Export the test site builder in Hugolib or something.
   38 func TestNewContentFromFile(t *testing.T) {
   39 	cases := []struct {
   40 		name     string
   41 		kind     string
   42 		path     string
   43 		expected any
   44 	}{
   45 		{"Post", "post", "post/sample-1.md", []string{`title = "Post Arch title"`, `test = "test1"`, "date = \"2015-01-12T19:20:04-07:00\""}},
   46 		{"Post org-mode", "post", "post/org-1.org", []string{`#+title: ORG-1`}},
   47 		{"Post, unknown content filetype", "post", "post/sample-1.pdoc", false},
   48 		{"Empty date", "emptydate", "post/sample-ed.md", []string{`title = "Empty Date Arch title"`, `test = "test1"`}},
   49 		{"Archetype file not found", "stump", "stump/sample-2.md", []string{`title: "Sample 2"`}}, // no archetype file
   50 		{"No archetype", "", "sample-3.md", []string{`title: "Sample 3"`}},                        // no archetype
   51 		{"Empty archetype", "product", "product/sample-4.md", []string{`title = "SAMPLE-4"`}},     // empty archetype front matter
   52 		{"Filenames", "filenames", "content/mypage/index.md", []string{"title = \"INDEX\"\n+++\n\n\nContentBaseName: mypage"}},
   53 		{"Branch Name", "name", "content/tags/tag-a/_index.md", []string{"+++\ntitle = 'Tag A'\n+++"}},
   54 
   55 		{"Lang 1", "lang", "post/lang-1.md", []string{`Site Lang: en|Name: Lang 1|i18n: Hugo Rocks!`}},
   56 		{"Lang 2", "lang", "post/lang-2.en.md", []string{`Site Lang: en|Name: Lang 2|i18n: Hugo Rocks!`}},
   57 		{"Lang nn file", "lang", "content/post/lang-3.nn.md", []string{`Site Lang: nn|Name: Lang 3|i18n: Hugo Rokkar!`}},
   58 		{"Lang nn dir", "lang", "content_nn/post/lang-4.md", []string{`Site Lang: nn|Name: Lang 4|i18n: Hugo Rokkar!`}},
   59 		{"Lang en in nn dir", "lang", "content_nn/post/lang-5.en.md", []string{`Site Lang: en|Name: Lang 5|i18n: Hugo Rocks!`}},
   60 		{"Lang en default", "lang", "post/my-bundle/index.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
   61 		{"Lang en file", "lang", "post/my-bundle/index.en.md", []string{`Site Lang: en|Name: My Bundle|i18n: Hugo Rocks!`}},
   62 		{"Lang nn bundle", "lang", "content/post/my-bundle/index.nn.md", []string{`Site Lang: nn|Name: My Bundle|i18n: Hugo Rokkar!`}},
   63 		{"Site", "site", "content/mypage/index.md", []string{"RegularPages .Site: 10", "RegularPages site: 10"}},
   64 		{"Shortcodes", "shortcodes", "shortcodes/go.md", []string{
   65 			`title = "GO"`,
   66 			"{{< myshortcode >}}",
   67 			"{{% myshortcode %}}",
   68 			"{{</* comment */>}}\n{{%/* comment */%}}",
   69 		}}, // shortcodes
   70 	}
   71 
   72 	c := qt.New(t)
   73 
   74 	for i, cas := range cases {
   75 		cas := cas
   76 
   77 		c.Run(cas.name, func(c *qt.C) {
   78 			c.Parallel()
   79 
   80 			mm := afero.NewMemMapFs()
   81 			c.Assert(initFs(mm), qt.IsNil)
   82 			cfg, fs := newTestCfg(c, mm)
   83 			h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
   84 			c.Assert(err, qt.IsNil)
   85 			err = create.NewContent(h, cas.kind, cas.path)
   86 
   87 			if b, ok := cas.expected.(bool); ok && !b {
   88 				if !b {
   89 					c.Assert(err, qt.Not(qt.IsNil))
   90 				}
   91 				return
   92 			}
   93 
   94 			c.Assert(err, qt.IsNil)
   95 
   96 			fname := filepath.FromSlash(cas.path)
   97 			if !strings.HasPrefix(fname, "content") {
   98 				fname = filepath.Join("content", fname)
   99 			}
  100 
  101 			content := readFileFromFs(c, fs.Source, fname)
  102 
  103 			for _, v := range cas.expected.([]string) {
  104 				found := strings.Contains(content, v)
  105 				if !found {
  106 					c.Fatalf("[%d] %q missing from output:\n%q", i, v, content)
  107 				}
  108 			}
  109 		})
  110 
  111 	}
  112 }
  113 
  114 func TestNewContentFromDir(t *testing.T) {
  115 	mm := afero.NewMemMapFs()
  116 	c := qt.New(t)
  117 
  118 	archetypeDir := filepath.Join("archetypes", "my-bundle")
  119 	c.Assert(mm.MkdirAll(archetypeDir, 0o755), qt.IsNil)
  120 
  121 	archetypeThemeDir := filepath.Join("themes", "mytheme", "archetypes", "my-theme-bundle")
  122 	c.Assert(mm.MkdirAll(archetypeThemeDir, 0o755), qt.IsNil)
  123 
  124 	contentFile := `
  125 File: %s
  126 Site Lang: {{ .Site.Language.Lang  }} 	
  127 Name: {{ replace .Name "-" " " | title }}
  128 i18n: {{ T "hugo" }}
  129 `
  130 
  131 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
  132 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.nn.md"), []byte(fmt.Sprintf(contentFile, "index.nn.md")), 0o755), qt.IsNil)
  133 
  134 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "pages", "bio.md"), []byte(fmt.Sprintf(contentFile, "bio.md")), 0o755), qt.IsNil)
  135 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
  136 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo2.xml"), []byte(`hugo2: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
  137 
  138 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
  139 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
  140 
  141 	c.Assert(initFs(mm), qt.IsNil)
  142 	cfg, fs := newTestCfg(c, mm)
  143 
  144 	h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
  145 	c.Assert(err, qt.IsNil)
  146 	c.Assert(len(h.Sites), qt.Equals, 2)
  147 
  148 	c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil)
  149 
  150 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
  151 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo2.xml")), `hugo2: {{ printf "no template handling in here" }}`)
  152 
  153 	// Content files should get the correct site context.
  154 	// TODO(bep) archetype check i18n
  155 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Post`, `i18n: Hugo Rocks!`)
  156 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.nn.md")), `File: index.nn.md`, `Site Lang: nn`, `Name: My Post`, `i18n: Hugo Rokkar!`)
  157 
  158 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Site Lang: en`, `Name: Bio`)
  159 
  160 	c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"), qt.IsNil)
  161 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Site Lang: en`, `Name: My Theme Post`, `i18n: Hugo Rocks!`)
  162 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
  163 }
  164 
  165 func TestNewContentFromDirSiteFunction(t *testing.T) {
  166 	mm := afero.NewMemMapFs()
  167 	c := qt.New(t)
  168 
  169 	archetypeDir := filepath.Join("archetypes", "my-bundle")
  170 	defaultArchetypeDir := filepath.Join("archetypes", "default")
  171 	c.Assert(mm.MkdirAll(archetypeDir, 0o755), qt.IsNil)
  172 	c.Assert(mm.MkdirAll(defaultArchetypeDir, 0o755), qt.IsNil)
  173 
  174 	contentFile := `
  175 File: %s
  176 site RegularPages: {{ len site.RegularPages  }} 	
  177 
  178 `
  179 
  180 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
  181 	c.Assert(afero.WriteFile(mm, filepath.Join(defaultArchetypeDir, "index.md"), []byte("default archetype index.md"), 0o755), qt.IsNil)
  182 
  183 	c.Assert(initFs(mm), qt.IsNil)
  184 	cfg, fs := newTestCfg(c, mm)
  185 
  186 	h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
  187 	c.Assert(err, qt.IsNil)
  188 	c.Assert(len(h.Sites), qt.Equals, 2)
  189 
  190 	c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil)
  191 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `site RegularPages: 10`)
  192 
  193 	// Default bundle archetype
  194 	c.Assert(create.NewContent(h, "", "post/my-post2"), qt.IsNil)
  195 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post2/index.md")), `default archetype index.md`)
  196 
  197 	// Regular file with bundle kind.
  198 	c.Assert(create.NewContent(h, "my-bundle", "post/foo.md"), qt.IsNil)
  199 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/foo.md")), `draft: true`)
  200 
  201 	// Regular files should fall back to the default archetype (we have no regular file archetype).
  202 	c.Assert(create.NewContent(h, "my-bundle", "mypage.md"), qt.IsNil)
  203 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "mypage.md")), `draft: true`)
  204 
  205 }
  206 
  207 func TestNewContentFromDirNoSite(t *testing.T) {
  208 	mm := afero.NewMemMapFs()
  209 	c := qt.New(t)
  210 
  211 	archetypeDir := filepath.Join("archetypes", "my-bundle")
  212 	c.Assert(mm.MkdirAll(archetypeDir, 0o755), qt.IsNil)
  213 
  214 	archetypeThemeDir := filepath.Join("themes", "mytheme", "archetypes", "my-theme-bundle")
  215 	c.Assert(mm.MkdirAll(archetypeThemeDir, 0o755), qt.IsNil)
  216 
  217 	contentFile := `
  218 File: %s
  219 Name: {{ replace .Name "-" " " | title }}
  220 i18n: {{ T "hugo" }}
  221 `
  222 
  223 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
  224 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "index.nn.md"), []byte(fmt.Sprintf(contentFile, "index.nn.md")), 0o755), qt.IsNil)
  225 
  226 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "pages", "bio.md"), []byte(fmt.Sprintf(contentFile, "bio.md")), 0o755), qt.IsNil)
  227 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
  228 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeDir, "resources", "hugo2.xml"), []byte(`hugo2: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
  229 
  230 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "index.md"), []byte(fmt.Sprintf(contentFile, "index.md")), 0o755), qt.IsNil)
  231 	c.Assert(afero.WriteFile(mm, filepath.Join(archetypeThemeDir, "resources", "hugo1.json"), []byte(`hugo1: {{ printf "no template handling in here" }}`), 0o755), qt.IsNil)
  232 
  233 	c.Assert(initFs(mm), qt.IsNil)
  234 	cfg, fs := newTestCfg(c, mm)
  235 
  236 	h, err := hugolib.NewHugoSites(deps.DepsCfg{Cfg: cfg, Fs: fs})
  237 	c.Assert(err, qt.IsNil)
  238 	c.Assert(len(h.Sites), qt.Equals, 2)
  239 
  240 	c.Assert(create.NewContent(h, "my-bundle", "post/my-post"), qt.IsNil)
  241 
  242 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
  243 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/resources/hugo2.xml")), `hugo2: {{ printf "no template handling in here" }}`)
  244 
  245 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.md")), `File: index.md`, `Name: My Post`, `i18n: Hugo Rocks!`)
  246 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/index.nn.md")), `File: index.nn.md`, `Name: My Post`, `i18n: Hugo Rokkar!`)
  247 
  248 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-post/pages/bio.md")), `File: bio.md`, `Name: Bio`)
  249 
  250 	c.Assert(create.NewContent(h, "my-theme-bundle", "post/my-theme-post"), qt.IsNil)
  251 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/index.md")), `File: index.md`, `Name: My Theme Post`, `i18n: Hugo Rocks!`)
  252 	cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "post/my-theme-post/resources/hugo1.json")), `hugo1: {{ printf "no template handling in here" }}`)
  253 }
  254 
  255 func initFs(fs afero.Fs) error {
  256 	perm := os.FileMode(0o755)
  257 	var err error
  258 
  259 	// create directories
  260 	dirs := []string{
  261 		"archetypes",
  262 		"content",
  263 		filepath.Join("themes", "sample", "archetypes"),
  264 	}
  265 	for _, dir := range dirs {
  266 		err = fs.Mkdir(dir, perm)
  267 		if err != nil && !os.IsExist(err) {
  268 			return err
  269 		}
  270 	}
  271 
  272 	// create some dummy content
  273 	for i := 1; i <= 10; i++ {
  274 		filename := filepath.Join("content", fmt.Sprintf("page%d.md", i))
  275 		afero.WriteFile(fs, filename, []byte(`---
  276 title: Test
  277 ---
  278 `), 0666)
  279 	}
  280 
  281 	// create archetype files
  282 	for _, v := range []struct {
  283 		path    string
  284 		content string
  285 	}{
  286 		{
  287 			path:    filepath.Join("archetypes", "post.md"),
  288 			content: "+++\ndate = \"2015-01-12T19:20:04-07:00\"\ntitle = \"Post Arch title\"\ntest = \"test1\"\n+++\n",
  289 		},
  290 		{
  291 			path:    filepath.Join("archetypes", "post.org"),
  292 			content: "#+title: {{ .BaseFileName  | upper }}",
  293 		},
  294 		{
  295 			path: filepath.Join("archetypes", "name.md"),
  296 			content: `+++
  297 title = '{{ replace .Name "-" " " | title }}'
  298 +++`,
  299 		},
  300 		{
  301 			path: filepath.Join("archetypes", "product.md"),
  302 			content: `+++
  303 title = "{{ .BaseFileName  | upper }}"
  304 +++`,
  305 		},
  306 		{
  307 			path: filepath.Join("archetypes", "filenames.md"),
  308 			content: `...
  309 title = "{{ .BaseFileName  | upper }}"
  310 +++
  311 
  312 
  313 ContentBaseName: {{ .File.ContentBaseName }}
  314 
  315 `,
  316 		},
  317 		{
  318 			path: filepath.Join("archetypes", "site.md"),
  319 			content: `...
  320 title = "{{ .BaseFileName  | upper }}"
  321 +++
  322 
  323 Len RegularPages .Site: {{ len .Site.RegularPages }}
  324 Len RegularPages site: {{ len site.RegularPages }}
  325 
  326 
  327 `,
  328 		},
  329 		{
  330 			path:    filepath.Join("archetypes", "emptydate.md"),
  331 			content: "+++\ndate =\"\"\ntitle = \"Empty Date Arch title\"\ntest = \"test1\"\n+++\n",
  332 		},
  333 		{
  334 			path:    filepath.Join("archetypes", "lang.md"),
  335 			content: `Site Lang: {{ site.Language.Lang  }}|Name: {{ replace .Name "-" " " | title }}|i18n: {{ T "hugo" }}`,
  336 		},
  337 		// #3623x
  338 		{
  339 			path: filepath.Join("archetypes", "shortcodes.md"),
  340 			content: `+++
  341 title = "{{ .BaseFileName  | upper }}"
  342 +++
  343 
  344 {{< myshortcode >}}
  345 
  346 Some text.
  347 
  348 {{% myshortcode %}}
  349 {{</* comment */>}}
  350 {{%/* comment */%}}
  351 
  352 
  353 `,
  354 		},
  355 	} {
  356 		f, err := fs.Create(v.path)
  357 		if err != nil {
  358 			return err
  359 		}
  360 		defer f.Close()
  361 
  362 		_, err = f.Write([]byte(v.content))
  363 		if err != nil {
  364 			return err
  365 		}
  366 	}
  367 
  368 	return nil
  369 }
  370 
  371 func cContains(c *qt.C, v any, matches ...string) {
  372 	for _, m := range matches {
  373 		c.Assert(v, qt.Contains, m)
  374 	}
  375 }
  376 
  377 // TODO(bep) extract common testing package with this and some others
  378 func readFileFromFs(t testing.TB, fs afero.Fs, filename string) string {
  379 	t.Helper()
  380 	filename = filepath.FromSlash(filename)
  381 	b, err := afero.ReadFile(fs, filename)
  382 	if err != nil {
  383 		// Print some debug info
  384 		root := strings.Split(filename, helpers.FilePathSeparator)[0]
  385 		afero.Walk(fs, root, func(path string, info os.FileInfo, err error) error {
  386 			if info != nil && !info.IsDir() {
  387 				fmt.Println("    ", path)
  388 			}
  389 
  390 			return nil
  391 		})
  392 		t.Fatalf("Failed to read file: %s", err)
  393 	}
  394 	return string(b)
  395 }
  396 
  397 func newTestCfg(c *qt.C, mm afero.Fs) (config.Provider, *hugofs.Fs) {
  398 	cfg := `
  399 
  400 theme = "mytheme"
  401 [languages]
  402 [languages.en]
  403 weight = 1
  404 languageName = "English"
  405 [languages.nn]
  406 weight = 2
  407 languageName = "Nynorsk"
  408 
  409 [module]
  410 [[module.mounts]]
  411   source = 'archetypes'
  412   target = 'archetypes'
  413 [[module.mounts]]
  414   source = 'content'
  415   target = 'content'
  416   lang = 'en'
  417 [[module.mounts]]
  418   source = 'content_nn'
  419   target = 'content'
  420   lang = 'nn'
  421 `
  422 	if mm == nil {
  423 		mm = afero.NewMemMapFs()
  424 	}
  425 
  426 	mm.MkdirAll(filepath.FromSlash("content_nn"), 0o777)
  427 
  428 	mm.MkdirAll(filepath.FromSlash("themes/mytheme"), 0o777)
  429 
  430 	c.Assert(afero.WriteFile(mm, filepath.Join("i18n", "en.toml"), []byte(`[hugo]
  431 other = "Hugo Rocks!"`), 0o755), qt.IsNil)
  432 	c.Assert(afero.WriteFile(mm, filepath.Join("i18n", "nn.toml"), []byte(`[hugo]
  433 other = "Hugo Rokkar!"`), 0o755), qt.IsNil)
  434 
  435 	c.Assert(afero.WriteFile(mm, "config.toml", []byte(cfg), 0o755), qt.IsNil)
  436 
  437 	v, _, err := hugolib.LoadConfig(hugolib.ConfigSourceDescriptor{Fs: mm, Filename: "config.toml"})
  438 	c.Assert(err, qt.IsNil)
  439 
  440 	return v, hugofs.NewFrom(mm, v)
  441 }