hugo

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

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

commands_test.go (11921B)

    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 commands
   15 
   16 import (
   17 	"fmt"
   18 	"io/ioutil"
   19 	"os"
   20 	"path/filepath"
   21 	"testing"
   22 
   23 	"github.com/gohugoio/hugo/config"
   24 
   25 	"github.com/spf13/afero"
   26 
   27 	"github.com/gohugoio/hugo/hugofs"
   28 
   29 	"github.com/gohugoio/hugo/common/types"
   30 
   31 	"github.com/spf13/cobra"
   32 
   33 	qt "github.com/frankban/quicktest"
   34 )
   35 
   36 func TestExecute(t *testing.T) {
   37 	c := qt.New(t)
   38 
   39 	createSite := func(c *qt.C) string {
   40 		dir := createSimpleTestSite(t, testSiteConfig{})
   41 		return dir
   42 	}
   43 
   44 	c.Run("hugo", func(c *qt.C) {
   45 		dir := createSite(c)
   46 		resp := Execute([]string{"-s=" + dir})
   47 		c.Assert(resp.Err, qt.IsNil)
   48 		result := resp.Result
   49 		c.Assert(len(result.Sites) == 1, qt.Equals, true)
   50 		c.Assert(len(result.Sites[0].RegularPages()) == 1, qt.Equals, true)
   51 		c.Assert(result.Sites[0].Info.Params()["myparam"], qt.Equals, "paramproduction")
   52 	})
   53 
   54 	c.Run("hugo, set environment", func(c *qt.C) {
   55 		dir := createSite(c)
   56 		resp := Execute([]string{"-s=" + dir, "-e=staging"})
   57 		c.Assert(resp.Err, qt.IsNil)
   58 		result := resp.Result
   59 		c.Assert(result.Sites[0].Info.Params()["myparam"], qt.Equals, "paramstaging")
   60 	})
   61 
   62 	c.Run("convert toJSON", func(c *qt.C) {
   63 		dir := createSite(c)
   64 		output := filepath.Join(dir, "myjson")
   65 		resp := Execute([]string{"convert", "toJSON", "-s=" + dir, "-e=staging", "-o=" + output})
   66 		c.Assert(resp.Err, qt.IsNil)
   67 		converted := readFileFrom(c, filepath.Join(output, "content", "p1.md"))
   68 		c.Assert(converted, qt.Equals, "{\n   \"title\": \"P1\",\n   \"weight\": 1\n}\n\nContent\n\n", qt.Commentf(converted))
   69 	})
   70 
   71 	c.Run("config, set environment", func(c *qt.C) {
   72 		dir := createSite(c)
   73 		out, err := captureStdout(func() error {
   74 			resp := Execute([]string{"config", "-s=" + dir, "-e=staging"})
   75 			return resp.Err
   76 		})
   77 		c.Assert(err, qt.IsNil)
   78 		c.Assert(out, qt.Contains, "params = map[myparam:paramstaging]", qt.Commentf(out))
   79 	})
   80 
   81 	c.Run("deploy, environment set", func(c *qt.C) {
   82 		dir := createSite(c)
   83 		resp := Execute([]string{"deploy", "-s=" + dir, "-e=staging", "--target=mydeployment", "--dryRun"})
   84 		c.Assert(resp.Err, qt.Not(qt.IsNil))
   85 		c.Assert(resp.Err.Error(), qt.Contains, `no driver registered for "hugocloud"`)
   86 	})
   87 
   88 	c.Run("list", func(c *qt.C) {
   89 		dir := createSite(c)
   90 		out, err := captureStdout(func() error {
   91 			resp := Execute([]string{"list", "all", "-s=" + dir, "-e=staging"})
   92 			return resp.Err
   93 		})
   94 		c.Assert(err, qt.IsNil)
   95 		c.Assert(out, qt.Contains, "p1.md")
   96 	})
   97 
   98 	c.Run("new theme", func(c *qt.C) {
   99 		dir := createSite(c)
  100 		themesDir := filepath.Join(dir, "mythemes")
  101 		resp := Execute([]string{"new", "theme", "mytheme", "-s=" + dir, "-e=staging", "--themesDir=" + themesDir})
  102 		c.Assert(resp.Err, qt.IsNil)
  103 		themeTOML := readFileFrom(c, filepath.Join(themesDir, "mytheme", "theme.toml"))
  104 		c.Assert(themeTOML, qt.Contains, "name = \"Mytheme\"")
  105 	})
  106 
  107 	c.Run("new site", func(c *qt.C) {
  108 		dir := createSite(c)
  109 		siteDir := filepath.Join(dir, "mysite")
  110 		resp := Execute([]string{"new", "site", siteDir, "-e=staging"})
  111 		c.Assert(resp.Err, qt.IsNil)
  112 		config := readFileFrom(c, filepath.Join(siteDir, "config.toml"))
  113 		c.Assert(config, qt.Contains, "baseURL = 'http://example.org/'")
  114 		checkNewSiteInited(c, siteDir)
  115 	})
  116 }
  117 
  118 func checkNewSiteInited(c *qt.C, basepath string) {
  119 	paths := []string{
  120 		filepath.Join(basepath, "layouts"),
  121 		filepath.Join(basepath, "content"),
  122 		filepath.Join(basepath, "archetypes"),
  123 		filepath.Join(basepath, "static"),
  124 		filepath.Join(basepath, "data"),
  125 		filepath.Join(basepath, "config.toml"),
  126 	}
  127 
  128 	for _, path := range paths {
  129 		_, err := os.Stat(path)
  130 		c.Assert(err, qt.IsNil)
  131 	}
  132 }
  133 
  134 func readFileFrom(c *qt.C, filename string) string {
  135 	c.Helper()
  136 	filename = filepath.Clean(filename)
  137 	b, err := afero.ReadFile(hugofs.Os, filename)
  138 	c.Assert(err, qt.IsNil)
  139 	return string(b)
  140 }
  141 
  142 func TestFlags(t *testing.T) {
  143 	c := qt.New(t)
  144 
  145 	noOpRunE := func(cmd *cobra.Command, args []string) error {
  146 		return nil
  147 	}
  148 
  149 	tests := []struct {
  150 		name  string
  151 		args  []string
  152 		check func(c *qt.C, cmd *serverCmd)
  153 	}{
  154 		{
  155 			// https://github.com/gohugoio/hugo/issues/7642
  156 			name: "ignoreVendorPaths",
  157 			args: []string{"server", "--ignoreVendorPaths=github.com/**"},
  158 			check: func(c *qt.C, cmd *serverCmd) {
  159 				cfg := config.NewWithTestDefaults()
  160 				cmd.flagsToConfig(cfg)
  161 				c.Assert(cfg.Get("ignoreVendorPaths"), qt.Equals, "github.com/**")
  162 			},
  163 		},
  164 		{
  165 			name: "Persistent flags",
  166 			args: []string{
  167 				"server",
  168 				"--config=myconfig.toml",
  169 				"--configDir=myconfigdir",
  170 				"--contentDir=mycontent",
  171 				"--disableKinds=page,home",
  172 				"--environment=testing",
  173 				"--configDir=myconfigdir",
  174 				"--layoutDir=mylayouts",
  175 				"--theme=mytheme",
  176 				"--gc",
  177 				"--themesDir=mythemes",
  178 				"--cleanDestinationDir",
  179 				"--navigateToChanged",
  180 				"--disableLiveReload",
  181 				"--noHTTPCache",
  182 				"--printI18nWarnings",
  183 				"--destination=/tmp/mydestination",
  184 				"-b=https://example.com/b/",
  185 				"--port=1366",
  186 				"--renderToDisk",
  187 				"--source=mysource",
  188 				"--printPathWarnings",
  189 				"--printUnusedTemplates",
  190 			},
  191 			check: func(c *qt.C, sc *serverCmd) {
  192 				c.Assert(sc, qt.Not(qt.IsNil))
  193 				c.Assert(sc.navigateToChanged, qt.Equals, true)
  194 				c.Assert(sc.disableLiveReload, qt.Equals, true)
  195 				c.Assert(sc.noHTTPCache, qt.Equals, true)
  196 				c.Assert(sc.renderToDisk, qt.Equals, true)
  197 				c.Assert(sc.serverPort, qt.Equals, 1366)
  198 				c.Assert(sc.environment, qt.Equals, "testing")
  199 
  200 				cfg := config.NewWithTestDefaults()
  201 				sc.flagsToConfig(cfg)
  202 				c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
  203 				c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
  204 				c.Assert(cfg.GetString("layoutDir"), qt.Equals, "mylayouts")
  205 				c.Assert(cfg.GetStringSlice("theme"), qt.DeepEquals, []string{"mytheme"})
  206 				c.Assert(cfg.GetString("themesDir"), qt.Equals, "mythemes")
  207 				c.Assert(cfg.GetString("baseURL"), qt.Equals, "https://example.com/b/")
  208 
  209 				c.Assert(cfg.Get("disableKinds"), qt.DeepEquals, []string{"page", "home"})
  210 
  211 				c.Assert(cfg.GetBool("gc"), qt.Equals, true)
  212 
  213 				// The flag is named printPathWarnings
  214 				c.Assert(cfg.GetBool("logPathWarnings"), qt.Equals, true)
  215 
  216 				// The flag is named printI18nWarnings
  217 				c.Assert(cfg.GetBool("logI18nWarnings"), qt.Equals, true)
  218 			},
  219 		},
  220 	}
  221 
  222 	for _, test := range tests {
  223 		c.Run(test.name, func(c *qt.C) {
  224 			b := newCommandsBuilder()
  225 			root := b.addAll().build()
  226 
  227 			for _, cmd := range b.commands {
  228 				if cmd.getCommand() == nil {
  229 					continue
  230 				}
  231 				// We are only intereseted in the flag handling here.
  232 				cmd.getCommand().RunE = noOpRunE
  233 			}
  234 			rootCmd := root.getCommand()
  235 			rootCmd.SetArgs(test.args)
  236 			c.Assert(rootCmd.Execute(), qt.IsNil)
  237 			test.check(c, b.commands[0].(*serverCmd))
  238 		})
  239 	}
  240 }
  241 
  242 func TestCommandsExecute(t *testing.T) {
  243 	c := qt.New(t)
  244 
  245 	dir := createSimpleTestSite(t, testSiteConfig{})
  246 	dirOut := t.TempDir()
  247 
  248 	sourceFlag := fmt.Sprintf("-s=%s", dir)
  249 
  250 	tests := []struct {
  251 		commands           []string
  252 		flags              []string
  253 		expectErrToContain string
  254 	}{
  255 		// TODO(bep) permission issue on my OSX? "operation not permitted" {[]string{"check", "ulimit"}, nil, false},
  256 		{[]string{"env"}, nil, ""},
  257 		{[]string{"version"}, nil, ""},
  258 		// no args = hugo build
  259 		{nil, []string{sourceFlag}, ""},
  260 		{nil, []string{sourceFlag, "--renderToMemory"}, ""},
  261 		{[]string{"completion", "bash"}, nil, ""},
  262 		{[]string{"completion", "fish"}, nil, ""},
  263 		{[]string{"completion", "powershell"}, nil, ""},
  264 		{[]string{"completion", "zsh"}, nil, ""},
  265 		{[]string{"config"}, []string{sourceFlag}, ""},
  266 		{[]string{"convert", "toTOML"}, []string{sourceFlag, "-o=" + filepath.Join(dirOut, "toml")}, ""},
  267 		{[]string{"convert", "toYAML"}, []string{sourceFlag, "-o=" + filepath.Join(dirOut, "yaml")}, ""},
  268 		{[]string{"convert", "toJSON"}, []string{sourceFlag, "-o=" + filepath.Join(dirOut, "json")}, ""},
  269 		{[]string{"gen", "chromastyles"}, []string{"--style=manni"}, ""},
  270 		{[]string{"gen", "doc"}, []string{"--dir=" + filepath.Join(dirOut, "doc")}, ""},
  271 		{[]string{"gen", "man"}, []string{"--dir=" + filepath.Join(dirOut, "man")}, ""},
  272 		{[]string{"list", "drafts"}, []string{sourceFlag}, ""},
  273 		{[]string{"list", "expired"}, []string{sourceFlag}, ""},
  274 		{[]string{"list", "future"}, []string{sourceFlag}, ""},
  275 		{[]string{"new", "new-page.md"}, []string{sourceFlag}, ""},
  276 		{[]string{"new", "site", filepath.Join(dirOut, "new-site")}, nil, ""},
  277 		{[]string{"unknowncommand"}, nil, "unknown command"},
  278 		// TODO(bep) cli refactor fix https://github.com/gohugoio/hugo/issues/4450
  279 		//{[]string{"new", "theme", filepath.Join(dirOut, "new-theme")}, nil,false},
  280 	}
  281 
  282 	for _, test := range tests {
  283 		name := "hugo"
  284 		if len(test.commands) > 0 {
  285 			name = test.commands[0]
  286 		}
  287 		c.Run(name, func(c *qt.C) {
  288 			b := newCommandsBuilder().addAll().build()
  289 			hugoCmd := b.getCommand()
  290 			test.flags = append(test.flags, "--quiet")
  291 			hugoCmd.SetArgs(append(test.commands, test.flags...))
  292 
  293 			// TODO(bep) capture output and add some simple asserts
  294 			// TODO(bep) misspelled subcommands does not return an error. We should investigate this
  295 			// but before that, check for "Error: unknown command".
  296 
  297 			_, err := hugoCmd.ExecuteC()
  298 			if test.expectErrToContain != "" {
  299 				c.Assert(err, qt.Not(qt.IsNil))
  300 				c.Assert(err.Error(), qt.Contains, test.expectErrToContain)
  301 			} else {
  302 				c.Assert(err, qt.IsNil)
  303 			}
  304 
  305 			// Assert that we have not left any development debug artifacts in
  306 			// the code.
  307 			if b.c != nil {
  308 				_, ok := b.c.publishDirFs.(types.DevMarker)
  309 				c.Assert(ok, qt.Equals, false)
  310 			}
  311 		})
  312 
  313 	}
  314 }
  315 
  316 type testSiteConfig struct {
  317 	configTOML string
  318 	contentDir string
  319 }
  320 
  321 func createSimpleTestSite(t testing.TB, cfg testSiteConfig) string {
  322 	dir := t.TempDir()
  323 
  324 	cfgStr := `
  325 
  326 baseURL = "https://example.org"
  327 title = "Hugo Commands"
  328 
  329 
  330 `
  331 
  332 	contentDir := "content"
  333 
  334 	if cfg.configTOML != "" {
  335 		cfgStr = cfg.configTOML
  336 	}
  337 	if cfg.contentDir != "" {
  338 		contentDir = cfg.contentDir
  339 	}
  340 
  341 	os.MkdirAll(filepath.Join(dir, "public"), 0777)
  342 
  343 	// Just the basic. These are for CLI tests, not site testing.
  344 	writeFile(t, filepath.Join(dir, "config.toml"), cfgStr)
  345 	writeFile(t, filepath.Join(dir, "config", "staging", "params.toml"), `myparam="paramstaging"`)
  346 	writeFile(t, filepath.Join(dir, "config", "staging", "deployment.toml"), `
  347 [[targets]]
  348 name = "mydeployment"
  349 URL = "hugocloud://hugotestbucket"
  350 `)
  351 
  352 	writeFile(t, filepath.Join(dir, "config", "testing", "params.toml"), `myparam="paramtesting"`)
  353 	writeFile(t, filepath.Join(dir, "config", "production", "params.toml"), `myparam="paramproduction"`)
  354 
  355 	writeFile(t, filepath.Join(dir, "static", "myfile.txt"), `Hello World!`)
  356 
  357 	writeFile(t, filepath.Join(dir, contentDir, "p1.md"), `
  358 ---
  359 title: "P1"
  360 weight: 1
  361 ---
  362 
  363 Content
  364 
  365 `)
  366 
  367 	writeFile(t, filepath.Join(dir, "layouts", "_default", "single.html"), `
  368 
  369 Single: {{ .Title }}
  370 
  371 `)
  372 
  373 	writeFile(t, filepath.Join(dir, "layouts", "_default", "list.html"), `
  374 
  375 List: {{ .Title }}
  376 Environment: {{ hugo.Environment }}
  377 
  378 For issue 9788:
  379 {{ $foo :="abc" | resources.FromString "foo.css" | minify | resources.PostProcess }}
  380 PostProcess: {{ $foo.RelPermalink }}
  381 
  382 `)
  383 
  384 	return dir
  385 }
  386 
  387 func writeFile(t testing.TB, filename, content string) {
  388 	must(t, os.MkdirAll(filepath.Dir(filename), os.FileMode(0755)))
  389 	must(t, ioutil.WriteFile(filename, []byte(content), os.FileMode(0755)))
  390 }
  391 
  392 func must(t testing.TB, err error) {
  393 	if err != nil {
  394 		t.Fatal(err)
  395 	}
  396 }