hugo

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

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

config_test.go (17460B)

    1 // Copyright 2016-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 	"bytes"
   18 	"fmt"
   19 	"path/filepath"
   20 	"strings"
   21 	"testing"
   22 
   23 	"github.com/gohugoio/hugo/config"
   24 
   25 	"github.com/gohugoio/hugo/media"
   26 	"github.com/google/go-cmp/cmp"
   27 
   28 	qt "github.com/frankban/quicktest"
   29 	"github.com/gohugoio/hugo/common/maps"
   30 	"github.com/spf13/afero"
   31 )
   32 
   33 func TestLoadConfig(t *testing.T) {
   34 
   35 	c := qt.New(t)
   36 
   37 	loadConfig := func(c *qt.C, configContent string, fromDir bool) config.Provider {
   38 		mm := afero.NewMemMapFs()
   39 		filename := "config.toml"
   40 		descriptor := ConfigSourceDescriptor{Fs: mm}
   41 		if fromDir {
   42 			filename = filepath.Join("config", "_default", filename)
   43 			descriptor.AbsConfigDir = "config"
   44 		}
   45 		writeToFs(t, mm, filename, configContent)
   46 		cfg, _, err := LoadConfig(descriptor)
   47 		c.Assert(err, qt.IsNil)
   48 		return cfg
   49 	}
   50 
   51 	c.Run("Basic", func(c *qt.C) {
   52 		c.Parallel()
   53 		// Add a random config variable for testing.
   54 		// side = page in Norwegian.
   55 		cfg := loadConfig(c, `PaginatePath = "side"`, false)
   56 		c.Assert(cfg.GetString("paginatePath"), qt.Equals, "side")
   57 	})
   58 
   59 	// Issue #8763
   60 	for _, fromDir := range []bool{false, true} {
   61 		testName := "Taxonomy overrides"
   62 		if fromDir {
   63 			testName += " from dir"
   64 		}
   65 		c.Run(testName, func(c *qt.C) {
   66 			c.Parallel()
   67 			cfg := loadConfig(c, `[taxonomies]
   68 appellation = "appellations"
   69 vigneron = "vignerons"`, fromDir)
   70 
   71 			c.Assert(cfg.Get("taxonomies"), qt.DeepEquals, maps.Params{
   72 				"appellation": "appellations",
   73 				"vigneron":    "vignerons",
   74 			})
   75 		})
   76 	}
   77 }
   78 
   79 func TestLoadMultiConfig(t *testing.T) {
   80 	t.Parallel()
   81 
   82 	c := qt.New(t)
   83 
   84 	// Add a random config variable for testing.
   85 	// side = page in Norwegian.
   86 	configContentBase := `
   87 	DontChange = "same"
   88 	PaginatePath = "side"
   89 	`
   90 	configContentSub := `
   91 	PaginatePath = "top"
   92 	`
   93 	mm := afero.NewMemMapFs()
   94 
   95 	writeToFs(t, mm, "base.toml", configContentBase)
   96 
   97 	writeToFs(t, mm, "override.toml", configContentSub)
   98 
   99 	cfg, _, err := LoadConfig(ConfigSourceDescriptor{Fs: mm, Filename: "base.toml,override.toml"})
  100 	c.Assert(err, qt.IsNil)
  101 
  102 	c.Assert(cfg.GetString("paginatePath"), qt.Equals, "top")
  103 	c.Assert(cfg.GetString("DontChange"), qt.Equals, "same")
  104 }
  105 
  106 func TestLoadConfigFromThemes(t *testing.T) {
  107 	t.Parallel()
  108 
  109 	c := qt.New(t)
  110 
  111 	mainConfigTemplate := `
  112 theme = "test-theme"
  113 baseURL = "https://example.com/"
  114 
  115 [frontmatter]
  116 date = ["date","publishDate"]
  117 
  118 [params]
  119 MERGE_PARAMS
  120 p1 = "p1 main"
  121 [params.b]
  122 b1 = "b1 main"
  123 [params.b.c]
  124 bc1 = "bc1 main"
  125 
  126 [mediaTypes]
  127 [mediaTypes."text/m1"]
  128 suffixes = ["m1main"]
  129 
  130 [outputFormats.o1]
  131 mediaType = "text/m1"
  132 baseName = "o1main"
  133 
  134 [languages]
  135 [languages.en]
  136 languageName = "English"
  137 [languages.en.params]
  138 pl1 = "p1-en-main"
  139 [languages.nb]
  140 languageName = "Norsk"
  141 [languages.nb.params]
  142 pl1 = "p1-nb-main"
  143 
  144 [[menu.main]]
  145 name = "menu-main-main"
  146 
  147 [[menu.top]]
  148 name = "menu-top-main"
  149 
  150 `
  151 
  152 	themeConfig := `
  153 baseURL = "http://bep.is/"
  154 
  155 # Can not be set in theme.
  156 disableKinds = ["taxonomy", "term"]
  157 
  158 # Can not be set in theme.
  159 [frontmatter]
  160 expiryDate = ["date"]
  161 
  162 [params]
  163 p1 = "p1 theme"
  164 p2 = "p2 theme"
  165 [params.b]
  166 b1 = "b1 theme"
  167 b2 = "b2 theme"
  168 [params.b.c]
  169 bc1 = "bc1 theme"
  170 bc2 = "bc2 theme"
  171 [params.b.c.d]
  172 bcd1 = "bcd1 theme"
  173 
  174 [mediaTypes]
  175 [mediaTypes."text/m1"]
  176 suffixes = ["m1theme"]
  177 [mediaTypes."text/m2"]
  178 suffixes = ["m2theme"]
  179 
  180 [outputFormats.o1]
  181 mediaType = "text/m1"
  182 baseName = "o1theme"
  183 [outputFormats.o2]
  184 mediaType = "text/m2"
  185 baseName = "o2theme"
  186 
  187 [languages]
  188 [languages.en]
  189 languageName = "English2"
  190 [languages.en.params]
  191 pl1 = "p1-en-theme"
  192 pl2 = "p2-en-theme"
  193 [[languages.en.menu.main]]
  194 name   = "menu-lang-en-main"
  195 [[languages.en.menu.theme]]
  196 name   = "menu-lang-en-theme"
  197 [languages.nb]
  198 languageName = "Norsk2"
  199 [languages.nb.params]
  200 pl1 = "p1-nb-theme"
  201 pl2 = "p2-nb-theme"
  202 top = "top-nb-theme"
  203 [[languages.nb.menu.main]]
  204 name   = "menu-lang-nb-main"
  205 [[languages.nb.menu.theme]]
  206 name   = "menu-lang-nb-theme"
  207 [[languages.nb.menu.top]]
  208 name   = "menu-lang-nb-top"
  209 
  210 [[menu.main]]
  211 name = "menu-main-theme"
  212 
  213 [[menu.thememenu]]
  214 name = "menu-theme"
  215 
  216 `
  217 
  218 	buildForConfig := func(t testing.TB, mainConfig, themeConfig string) *sitesBuilder {
  219 		b := newTestSitesBuilder(t)
  220 		b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig)
  221 		return b.Build(BuildCfg{})
  222 	}
  223 
  224 	buildForStrategy := func(t testing.TB, s string) *sitesBuilder {
  225 		mainConfig := strings.ReplaceAll(mainConfigTemplate, "MERGE_PARAMS", s)
  226 		return buildForConfig(t, mainConfig, themeConfig)
  227 	}
  228 
  229 	c.Run("Merge default", func(c *qt.C) {
  230 		b := buildForStrategy(c, "")
  231 
  232 		got := b.Cfg.Get("").(maps.Params)
  233 
  234 		// Issue #8866
  235 		b.Assert(b.Cfg.Get("disableKinds"), qt.IsNil)
  236 
  237 		b.Assert(got["params"], qt.DeepEquals, maps.Params{
  238 			"b": maps.Params{
  239 				"b1": "b1 main",
  240 				"c": maps.Params{
  241 					"bc1": "bc1 main",
  242 					"bc2": "bc2 theme",
  243 					"d":   maps.Params{"bcd1": string("bcd1 theme")},
  244 				},
  245 				"b2": "b2 theme",
  246 			},
  247 			"p2": "p2 theme",
  248 			"p1": "p1 main",
  249 		})
  250 
  251 		b.Assert(got["mediatypes"], qt.DeepEquals, maps.Params{
  252 			"text/m2": maps.Params{
  253 				"suffixes": []any{
  254 					"m2theme",
  255 				},
  256 			},
  257 			"text/m1": maps.Params{
  258 				"suffixes": []any{
  259 					"m1main",
  260 				},
  261 			},
  262 		})
  263 
  264 		var eq = qt.CmpEquals(
  265 			cmp.Comparer(func(m1, m2 media.Type) bool {
  266 				if m1.SubType != m2.SubType {
  267 					return false
  268 				}
  269 				return m1.FirstSuffix == m2.FirstSuffix
  270 			}),
  271 		)
  272 
  273 		mediaTypes := b.H.Sites[0].mediaTypesConfig
  274 		m1, _ := mediaTypes.GetByType("text/m1")
  275 		m2, _ := mediaTypes.GetByType("text/m2")
  276 
  277 		b.Assert(got["outputformats"], eq, maps.Params{
  278 			"o1": maps.Params{
  279 				"mediatype": m1,
  280 				"basename":  "o1main",
  281 			},
  282 			"o2": maps.Params{
  283 				"basename":  "o2theme",
  284 				"mediatype": m2,
  285 			},
  286 		})
  287 
  288 		b.Assert(got["languages"], qt.DeepEquals, maps.Params{
  289 			"en": maps.Params{
  290 				"languagename": "English",
  291 				"params": maps.Params{
  292 					"pl2": "p2-en-theme",
  293 					"pl1": "p1-en-main",
  294 				},
  295 				"menus": maps.Params{
  296 					"main": []any{
  297 						map[string]any{
  298 							"name": "menu-lang-en-main",
  299 						},
  300 					},
  301 					"theme": []any{
  302 						map[string]any{
  303 							"name": "menu-lang-en-theme",
  304 						},
  305 					},
  306 				},
  307 			},
  308 			"nb": maps.Params{
  309 				"languagename": "Norsk",
  310 				"params": maps.Params{
  311 					"top": "top-nb-theme",
  312 					"pl1": "p1-nb-main",
  313 					"pl2": "p2-nb-theme",
  314 				},
  315 				"menus": maps.Params{
  316 					"main": []any{
  317 						map[string]any{
  318 							"name": "menu-lang-nb-main",
  319 						},
  320 					},
  321 					"theme": []any{
  322 						map[string]any{
  323 							"name": "menu-lang-nb-theme",
  324 						},
  325 					},
  326 					"top": []any{
  327 						map[string]any{
  328 							"name": "menu-lang-nb-top",
  329 						},
  330 					},
  331 				},
  332 			},
  333 		})
  334 
  335 		c.Assert(got["baseurl"], qt.Equals, "https://example.com/")
  336 	})
  337 
  338 	c.Run("Merge shallow", func(c *qt.C) {
  339 		b := buildForStrategy(c, fmt.Sprintf("_merge=%q", "shallow"))
  340 
  341 		got := b.Cfg.Get("").(maps.Params)
  342 
  343 		// Shallow merge, only add new keys to params.
  344 		b.Assert(got["params"], qt.DeepEquals, maps.Params{
  345 			"p1": "p1 main",
  346 			"b": maps.Params{
  347 				"b1": "b1 main",
  348 				"c": maps.Params{
  349 					"bc1": "bc1 main",
  350 				},
  351 			},
  352 			"p2": "p2 theme",
  353 		})
  354 	})
  355 
  356 	c.Run("Merge no params in project", func(c *qt.C) {
  357 		b := buildForConfig(
  358 			c,
  359 			"baseURL=\"https://example.org\"\ntheme = \"test-theme\"\n",
  360 			"[params]\np1 = \"p1 theme\"\n",
  361 		)
  362 
  363 		got := b.Cfg.Get("").(maps.Params)
  364 
  365 		b.Assert(got["params"], qt.DeepEquals, maps.Params{
  366 			"p1": "p1 theme",
  367 		})
  368 	})
  369 
  370 	c.Run("Merge language no menus or params in project", func(c *qt.C) {
  371 		b := buildForConfig(
  372 			c,
  373 			`
  374 theme = "test-theme"
  375 baseURL = "https://example.com/"
  376 
  377 [languages]
  378 [languages.en]
  379 languageName = "English"
  380 
  381 `,
  382 			`
  383 [languages]
  384 [languages.en]
  385 languageName = "EnglishTheme"
  386 
  387 [languages.en.params]
  388 p1="themep1"
  389 
  390 [[languages.en.menus.main]]
  391 name   = "menu-theme"
  392 `,
  393 		)
  394 
  395 		got := b.Cfg.Get("").(maps.Params)
  396 
  397 		b.Assert(got["languages"], qt.DeepEquals,
  398 			maps.Params{
  399 				"en": maps.Params{
  400 					"languagename": "English",
  401 					"menus": maps.Params{
  402 						"main": []any{
  403 							map[string]any{
  404 								"name": "menu-theme",
  405 							},
  406 						},
  407 					},
  408 					"params": maps.Params{
  409 						"p1": "themep1",
  410 					},
  411 				},
  412 			},
  413 		)
  414 	})
  415 
  416 	// Issue #8724
  417 	for _, mergeStrategy := range []string{"none", "shallow"} {
  418 		c.Run(fmt.Sprintf("Merge with sitemap config in theme, mergestrategy %s", mergeStrategy), func(c *qt.C) {
  419 
  420 			smapConfigTempl := `[sitemap]
  421   changefreq = %q
  422   filename = "sitemap.xml"
  423   priority = 0.5`
  424 
  425 			b := buildForConfig(
  426 				c,
  427 				fmt.Sprintf("_merge=%q\nbaseURL=\"https://example.org\"\ntheme = \"test-theme\"\n", mergeStrategy),
  428 				"baseURL=\"http://example.com\"\n"+fmt.Sprintf(smapConfigTempl, "monthly"),
  429 			)
  430 
  431 			got := b.Cfg.Get("").(maps.Params)
  432 
  433 			if mergeStrategy == "none" {
  434 				b.Assert(got["sitemap"], qt.DeepEquals, maps.Params{
  435 					"priority": int(-1),
  436 					"filename": "sitemap.xml",
  437 				})
  438 
  439 				b.AssertFileContent("public/sitemap.xml", "schemas/sitemap")
  440 			} else {
  441 				b.Assert(got["sitemap"], qt.DeepEquals, maps.Params{
  442 					"priority":   int(-1),
  443 					"filename":   "sitemap.xml",
  444 					"changefreq": "monthly",
  445 				})
  446 
  447 				b.AssertFileContent("public/sitemap.xml", "<changefreq>monthly</changefreq>")
  448 			}
  449 
  450 		})
  451 	}
  452 
  453 }
  454 
  455 func TestLoadConfigFromThemeDir(t *testing.T) {
  456 	t.Parallel()
  457 
  458 	mainConfig := `
  459 theme = "test-theme"
  460 
  461 [params]
  462 m1 = "mv1"	
  463 `
  464 
  465 	themeConfig := `
  466 [params]
  467 t1 = "tv1"	
  468 t2 = "tv2"
  469 `
  470 
  471 	themeConfigDir := filepath.Join("themes", "test-theme", "config")
  472 	themeConfigDirDefault := filepath.Join(themeConfigDir, "_default")
  473 	themeConfigDirProduction := filepath.Join(themeConfigDir, "production")
  474 
  475 	projectConfigDir := "config"
  476 
  477 	b := newTestSitesBuilder(t)
  478 	b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig)
  479 	b.Assert(b.Fs.Source.MkdirAll(themeConfigDirDefault, 0777), qt.IsNil)
  480 	b.Assert(b.Fs.Source.MkdirAll(themeConfigDirProduction, 0777), qt.IsNil)
  481 	b.Assert(b.Fs.Source.MkdirAll(projectConfigDir, 0777), qt.IsNil)
  482 
  483 	b.WithSourceFile(filepath.Join(projectConfigDir, "config.toml"), `[params]
  484 m2 = "mv2"
  485 `)
  486 	b.WithSourceFile(filepath.Join(themeConfigDirDefault, "config.toml"), `[params]
  487 t2 = "tv2d"
  488 t3 = "tv3d"
  489 `)
  490 
  491 	b.WithSourceFile(filepath.Join(themeConfigDirProduction, "config.toml"), `[params]
  492 t3 = "tv3p"
  493 `)
  494 
  495 	b.Build(BuildCfg{})
  496 
  497 	got := b.Cfg.Get("params").(maps.Params)
  498 
  499 	b.Assert(got, qt.DeepEquals, maps.Params{
  500 		"t3": "tv3p",
  501 		"m1": "mv1",
  502 		"t1": "tv1",
  503 		"t2": "tv2d",
  504 	})
  505 
  506 }
  507 
  508 func TestPrivacyConfig(t *testing.T) {
  509 	t.Parallel()
  510 
  511 	c := qt.New(t)
  512 
  513 	tomlConfig := `
  514 
  515 someOtherValue = "foo"
  516 
  517 [privacy]
  518 [privacy.youtube]
  519 privacyEnhanced = true
  520 `
  521 
  522 	b := newTestSitesBuilder(t)
  523 	b.WithConfigFile("toml", tomlConfig)
  524 	b.Build(BuildCfg{SkipRender: true})
  525 
  526 	c.Assert(b.H.Sites[0].Info.Config().Privacy.YouTube.PrivacyEnhanced, qt.Equals, true)
  527 }
  528 
  529 func TestLoadConfigModules(t *testing.T) {
  530 	t.Parallel()
  531 
  532 	c := qt.New(t)
  533 
  534 	// https://github.com/gohugoio/hugoThemes#themetoml
  535 
  536 	const (
  537 		// Before Hugo 0.56 each theme/component could have its own theme.toml
  538 		// with some settings, mostly used on the Hugo themes site.
  539 		// To preserve combability we read these files into the new "modules"
  540 		// section in config.toml.
  541 		o1t = `
  542 name = "Component o1"
  543 license = "MIT"
  544 min_version = 0.38
  545 `
  546 		// This is the component's config.toml, using the old theme syntax.
  547 		o1c = `
  548 theme = ["n2"]
  549 `
  550 
  551 		n1 = `
  552 title = "Component n1"
  553 
  554 [module]
  555 description = "Component n1 description"
  556 [module.hugoVersion]
  557 min = "0.40.0"
  558 max = "0.50.0"
  559 extended = true
  560 [[module.imports]]
  561 path="o1"
  562 [[module.imports]]
  563 path="n3"
  564 
  565 
  566 `
  567 
  568 		n2 = `
  569 title = "Component n2"
  570 `
  571 
  572 		n3 = `
  573 title = "Component n3"
  574 `
  575 
  576 		n4 = `
  577 title = "Component n4"
  578 `
  579 	)
  580 
  581 	b := newTestSitesBuilder(t)
  582 
  583 	writeThemeFiles := func(name, configTOML, themeTOML string) {
  584 		b.WithSourceFile(filepath.Join("themes", name, "data", "module.toml"), fmt.Sprintf("name=%q", name))
  585 		if configTOML != "" {
  586 			b.WithSourceFile(filepath.Join("themes", name, "config.toml"), configTOML)
  587 		}
  588 		if themeTOML != "" {
  589 			b.WithSourceFile(filepath.Join("themes", name, "theme.toml"), themeTOML)
  590 		}
  591 	}
  592 
  593 	writeThemeFiles("n1", n1, "")
  594 	writeThemeFiles("n2", n2, "")
  595 	writeThemeFiles("n3", n3, "")
  596 	writeThemeFiles("n4", n4, "")
  597 	writeThemeFiles("o1", o1c, o1t)
  598 
  599 	b.WithConfigFile("toml", `
  600 [module]
  601 [[module.imports]]
  602 path="n1"
  603 [[module.imports]]
  604 path="n4"
  605 
  606 `)
  607 
  608 	b.Build(BuildCfg{})
  609 
  610 	modulesClient := b.H.Paths.ModulesClient
  611 	var graphb bytes.Buffer
  612 	modulesClient.Graph(&graphb)
  613 
  614 	expected := `project n1
  615 n1 o1
  616 o1 n2
  617 n1 n3
  618 project n4
  619 `
  620 
  621 	c.Assert(graphb.String(), qt.Equals, expected)
  622 }
  623 
  624 func TestLoadConfigWithOsEnvOverrides(t *testing.T) {
  625 	c := qt.New(t)
  626 
  627 	baseConfig := `
  628 
  629 theme = "mytheme"
  630 environment = "production"
  631 enableGitInfo = true
  632 intSlice = [5,7,9]
  633 floatSlice = [3.14, 5.19]
  634 stringSlice = ["a", "b"]
  635 
  636 [outputFormats]
  637 [outputFormats.ofbase]
  638 mediaType = "text/plain"
  639 
  640 [params]
  641 paramWithNoEnvOverride="nooverride"
  642 [params.api_config]
  643 api_key="default_key"
  644 another_key="default another_key"
  645 
  646 [imaging]
  647 anchor = "smart"
  648 quality = 75 
  649 `
  650 
  651 	newB := func(t testing.TB) *sitesBuilder {
  652 		b := newTestSitesBuilder(t).WithConfigFile("toml", baseConfig)
  653 
  654 		b.WithSourceFile("themes/mytheme/config.toml", `
  655 
  656 [outputFormats]
  657 [outputFormats.oftheme]
  658 mediaType = "text/plain"
  659 [outputFormats.ofbase]
  660 mediaType = "application/xml"
  661 
  662 [params]
  663 [params.mytheme_section]
  664 theme_param="themevalue"
  665 theme_param_nooverride="nooverride"
  666 [params.mytheme_section2]
  667 theme_param="themevalue2"
  668 
  669 `)
  670 
  671 		return b
  672 	}
  673 
  674 	c.Run("Variations", func(c *qt.C) {
  675 
  676 		b := newB(c)
  677 
  678 		b.WithEnviron(
  679 			"HUGO_ENVIRONMENT", "test",
  680 			"HUGO_NEW", "new", // key not in config.toml
  681 			"HUGO_ENABLEGITINFO", "false",
  682 			"HUGO_IMAGING_ANCHOR", "top",
  683 			"HUGO_IMAGING_RESAMPLEFILTER", "CatmullRom",
  684 			"HUGO_STRINGSLICE", `["c", "d"]`,
  685 			"HUGO_INTSLICE", `[5, 8, 9]`,
  686 			"HUGO_FLOATSLICE", `[5.32]`,
  687 			// Issue #7829
  688 			"HUGOxPARAMSxAPI_CONFIGxAPI_KEY", "new_key",
  689 			// Delimiters are case sensitive.
  690 			"HUGOxPARAMSxAPI_CONFIGXANOTHER_KEY", "another_key",
  691 			// Issue #8346
  692 			"HUGOxPARAMSxMYTHEME_SECTIONxTHEME_PARAM", "themevalue_changed",
  693 			"HUGOxPARAMSxMYTHEME_SECTION2xTHEME_PARAM", "themevalue2_changed",
  694 			"HUGO_PARAMS_EMPTY", ``,
  695 			"HUGO_PARAMS_HTML", `<a target="_blank" />`,
  696 			// Issue #8618
  697 			"HUGO_SERVICES_GOOGLEANALYTICS_ID", `gaid`,
  698 			"HUGO_PARAMS_A_B_C", "abc",
  699 		)
  700 
  701 		b.Build(BuildCfg{})
  702 
  703 		cfg := b.H.Cfg
  704 		s := b.H.Sites[0]
  705 		scfg := s.siteConfigConfig.Services
  706 
  707 		c.Assert(cfg.Get("environment"), qt.Equals, "test")
  708 		c.Assert(cfg.GetBool("enablegitinfo"), qt.Equals, false)
  709 		c.Assert(cfg.Get("new"), qt.Equals, "new")
  710 		c.Assert(cfg.Get("imaging.anchor"), qt.Equals, "top")
  711 		c.Assert(cfg.Get("imaging.quality"), qt.Equals, int64(75))
  712 		c.Assert(cfg.Get("imaging.resamplefilter"), qt.Equals, "CatmullRom")
  713 		c.Assert(cfg.Get("stringSlice"), qt.DeepEquals, []any{"c", "d"})
  714 		c.Assert(cfg.Get("floatSlice"), qt.DeepEquals, []any{5.32})
  715 		c.Assert(cfg.Get("intSlice"), qt.DeepEquals, []any{5, 8, 9})
  716 		c.Assert(cfg.Get("params.api_config.api_key"), qt.Equals, "new_key")
  717 		c.Assert(cfg.Get("params.api_config.another_key"), qt.Equals, "default another_key")
  718 		c.Assert(cfg.Get("params.mytheme_section.theme_param"), qt.Equals, "themevalue_changed")
  719 		c.Assert(cfg.Get("params.mytheme_section.theme_param_nooverride"), qt.Equals, "nooverride")
  720 		c.Assert(cfg.Get("params.mytheme_section2.theme_param"), qt.Equals, "themevalue2_changed")
  721 		c.Assert(cfg.Get("params.empty"), qt.Equals, ``)
  722 		c.Assert(cfg.Get("params.html"), qt.Equals, `<a target="_blank" />`)
  723 
  724 		params := cfg.Get("params").(maps.Params)
  725 		c.Assert(params["paramwithnoenvoverride"], qt.Equals, "nooverride")
  726 		c.Assert(cfg.Get("params.paramwithnoenvoverride"), qt.Equals, "nooverride")
  727 		c.Assert(scfg.GoogleAnalytics.ID, qt.Equals, "gaid")
  728 		c.Assert(cfg.Get("params.a.b"), qt.DeepEquals, maps.Params{
  729 			"c": "abc",
  730 		})
  731 
  732 		ofBase, _ := s.outputFormatsConfig.GetByName("ofbase")
  733 		ofTheme, _ := s.outputFormatsConfig.GetByName("oftheme")
  734 
  735 		c.Assert(ofBase.MediaType, qt.Equals, media.TextType)
  736 		c.Assert(ofTheme.MediaType, qt.Equals, media.TextType)
  737 
  738 	})
  739 
  740 	// Issue #8709
  741 	c.Run("Set in string", func(c *qt.C) {
  742 		b := newB(c)
  743 
  744 		b.WithEnviron(
  745 			"HUGO_ENABLEGITINFO", "false",
  746 			// imaging.anchor is a string, and it's not possible
  747 			// to set a child attribute.
  748 			"HUGO_IMAGING_ANCHOR_FOO", "top",
  749 		)
  750 
  751 		b.Build(BuildCfg{})
  752 
  753 		cfg := b.H.Cfg
  754 		c.Assert(cfg.Get("imaging.anchor"), qt.Equals, "smart")
  755 
  756 	})
  757 
  758 }
  759 
  760 func TestInvalidDefaultMarkdownHandler(t *testing.T) {
  761 	t.Parallel()
  762 
  763 	files := `
  764 -- config.toml --
  765 [markup]
  766 defaultMarkdownHandler = 'blackfriday'
  767 -- content/_index.md --
  768 ## Foo
  769 -- layouts/index.html --
  770 {{ .Content }}
  771 
  772 `
  773 
  774 	b, err := NewIntegrationTestBuilder(
  775 		IntegrationTestConfig{
  776 			T:           t,
  777 			TxtarString: files,
  778 		},
  779 	).BuildE()
  780 
  781 	b.Assert(err, qt.IsNotNil)
  782 	b.Assert(err.Error(), qt.Contains, "Configured defaultMarkdownHandler \"blackfriday\" not found. Did you mean to use goldmark? Blackfriday was removed in Hugo v0.100.0.")
  783 
  784 }