// Copyright 2016-present The Hugo Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package hugolib import ( "bytes" "fmt" "path/filepath" "testing" "github.com/spf13/afero" "github.com/spf13/viper" "github.com/stretchr/testify/require" ) func TestLoadConfig(t *testing.T) { t.Parallel() assert := require.New(t) // Add a random config variable for testing. // side = page in Norwegian. configContent := ` PaginatePath = "side" ` mm := afero.NewMemMapFs() writeToFs(t, mm, "hugo.toml", configContent) cfg, _, err := LoadConfig(ConfigSourceDescriptor{Fs: mm, Filename: "hugo.toml"}) require.NoError(t, err) assert.Equal("side", cfg.GetString("paginatePath")) } func TestLoadMultiConfig(t *testing.T) { t.Parallel() assert := require.New(t) // Add a random config variable for testing. // side = page in Norwegian. configContentBase := ` DontChange = "same" PaginatePath = "side" ` configContentSub := ` PaginatePath = "top" ` mm := afero.NewMemMapFs() writeToFs(t, mm, "base.toml", configContentBase) writeToFs(t, mm, "override.toml", configContentSub) cfg, _, err := LoadConfig(ConfigSourceDescriptor{Fs: mm, Filename: "base.toml,override.toml"}) require.NoError(t, err) assert.Equal("top", cfg.GetString("paginatePath")) assert.Equal("same", cfg.GetString("DontChange")) } func TestLoadConfigFromTheme(t *testing.T) { t.Parallel() assert := require.New(t) mainConfigBasic := ` theme = "test-theme" baseURL = "https://example.com/" ` mainConfig := ` theme = "test-theme" baseURL = "https://example.com/" [frontmatter] date = ["date","publishDate"] [params] p1 = "p1 main" p2 = "p2 main" top = "top" [mediaTypes] [mediaTypes."text/m1"] suffixes = ["m1main"] [outputFormats.o1] mediaType = "text/m1" baseName = "o1main" [languages] [languages.en] languageName = "English" [languages.en.params] pl1 = "p1-en-main" [languages.nb] languageName = "Norsk" [languages.nb.params] pl1 = "p1-nb-main" [[menu.main]] name = "menu-main-main" [[menu.top]] name = "menu-top-main" ` themeConfig := ` baseURL = "http://bep.is/" # Can not be set in theme. [frontmatter] expiryDate = ["date"] [params] p1 = "p1 theme" p2 = "p2 theme" p3 = "p3 theme" [mediaTypes] [mediaTypes."text/m1"] suffixes = ["m1theme"] [mediaTypes."text/m2"] suffixes = ["m2theme"] [outputFormats.o1] mediaType = "text/m1" baseName = "o1theme" [outputFormats.o2] mediaType = "text/m2" baseName = "o2theme" [languages] [languages.en] languageName = "English2" [languages.en.params] pl1 = "p1-en-theme" pl2 = "p2-en-theme" [[languages.en.menu.main]] name = "menu-lang-en-main" [[languages.en.menu.theme]] name = "menu-lang-en-theme" [languages.nb] languageName = "Norsk2" [languages.nb.params] pl1 = "p1-nb-theme" pl2 = "p2-nb-theme" top = "top-nb-theme" [[languages.nb.menu.main]] name = "menu-lang-nb-main" [[languages.nb.menu.theme]] name = "menu-lang-nb-theme" [[languages.nb.menu.top]] name = "menu-lang-nb-top" [[menu.main]] name = "menu-main-theme" [[menu.thememenu]] name = "menu-theme" ` b := newTestSitesBuilder(t) b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig) b.CreateSites().Build(BuildCfg{}) got := b.Cfg.(*viper.Viper).AllSettings() b.AssertObject(` map[string]interface {}{ "p1": "p1 main", "p2": "p2 main", "p3": "p3 theme", "top": "top", }`, got["params"]) b.AssertObject(` map[string]interface {}{ "date": []interface {}{ "date", "publishDate", }, }`, got["frontmatter"]) b.AssertObject(` map[string]interface {}{ "text/m1": map[string]interface {}{ "suffixes": []interface {}{ "m1main", }, }, "text/m2": map[string]interface {}{ "suffixes": []interface {}{ "m2theme", }, }, }`, got["mediatypes"]) b.AssertObject(` map[string]interface {}{ "o1": map[string]interface {}{ "basename": "o1main", "mediatype": Type{ MainType: "text", SubType: "m1", Delimiter: ".", Suffixes: []string{ "m1main", }, }, }, "o2": map[string]interface {}{ "basename": "o2theme", "mediatype": Type{ MainType: "text", SubType: "m2", Delimiter: ".", Suffixes: []string{ "m2theme", }, }, }, }`, got["outputformats"]) b.AssertObject(`map[string]interface {}{ "en": map[string]interface {}{ "languagename": "English", "menus": map[string]interface {}{ "theme": []map[string]interface {}{ map[string]interface {}{ "name": "menu-lang-en-theme", }, }, }, "params": map[string]interface {}{ "pl1": "p1-en-main", "pl2": "p2-en-theme", }, }, "nb": map[string]interface {}{ "languagename": "Norsk", "menus": map[string]interface {}{ "theme": []map[string]interface {}{ map[string]interface {}{ "name": "menu-lang-nb-theme", }, }, }, "params": map[string]interface {}{ "pl1": "p1-nb-main", "pl2": "p2-nb-theme", }, }, } `, got["languages"]) b.AssertObject(` map[string]interface {}{ "main": []map[string]interface {}{ map[string]interface {}{ "name": "menu-main-main", }, }, "thememenu": []map[string]interface {}{ map[string]interface {}{ "name": "menu-theme", }, }, "top": []map[string]interface {}{ map[string]interface {}{ "name": "menu-top-main", }, }, } `, got["menus"]) assert.Equal("https://example.com/", got["baseurl"]) if true { return } // Test variants with only values from theme b = newTestSitesBuilder(t) b.WithConfigFile("toml", mainConfigBasic).WithThemeConfigFile("toml", themeConfig) b.CreateSites().Build(BuildCfg{}) got = b.Cfg.(*viper.Viper).AllSettings() b.AssertObject(`map[string]interface {}{ "p1": "p1 theme", "p2": "p2 theme", "p3": "p3 theme", "test-theme": map[string]interface {}{ "p1": "p1 theme", "p2": "p2 theme", "p3": "p3 theme", }, }`, got["params"]) assert.Nil(got["languages"]) b.AssertObject(` map[string]interface {}{ "text/m1": map[string]interface {}{ "suffix": "m1theme", }, "text/m2": map[string]interface {}{ "suffix": "m2theme", }, }`, got["mediatypes"]) b.AssertObject(` map[string]interface {}{ "o1": map[string]interface {}{ "basename": "o1theme", "mediatype": Type{ MainType: "text", SubType: "m1", Suffix: "m1theme", Delimiter: ".", }, }, "o2": map[string]interface {}{ "basename": "o2theme", "mediatype": Type{ MainType: "text", SubType: "m2", Suffix: "m2theme", Delimiter: ".", }, }, }`, got["outputformats"]) b.AssertObject(` map[string]interface {}{ "main": []interface {}{ map[string]interface {}{ "name": "menu-main-theme", }, }, "thememenu": []interface {}{ map[string]interface {}{ "name": "menu-theme", }, }, }`, got["menu"]) } func TestPrivacyConfig(t *testing.T) { t.Parallel() assert := require.New(t) tomlConfig := ` someOtherValue = "foo" [privacy] [privacy.youtube] privacyEnhanced = true ` b := newTestSitesBuilder(t) b.WithConfigFile("toml", tomlConfig) b.Build(BuildCfg{SkipRender: true}) assert.True(b.H.Sites[0].Info.Config().Privacy.YouTube.PrivacyEnhanced) } func TestLoadConfigModules(t *testing.T) { t.Parallel() assert := require.New(t) // https://github.com/gohugoio/hugoThemes#themetoml const ( // Before Hugo 0.56 each theme/component could have its own theme.toml // with some settings, mostly used on the Hugo themes site. // To preserve combability we read these files into the new "modules" // section in config.toml. o1t = ` name = "Component o1" license = "MIT" min_version = 0.38 ` // This is the component's config.toml, using the old theme syntax. o1c = ` theme = ["n2"] ` n1 = ` title = "Component n1" [module] description = "Component n1 description" [module.hugoVersion] min = "0.40.0" max = "0.50.0" extended = true [[module.imports]] path="o1" [[module.imports]] path="n3" ` n2 = ` title = "Component n2" ` n3 = ` title = "Component n3" ` n4 = ` title = "Component n4" ` ) b := newTestSitesBuilder(t) writeThemeFiles := func(name, configTOML, themeTOML string) { b.WithSourceFile(filepath.Join("themes", name, "data", "module.toml"), fmt.Sprintf("name=%q", name)) if configTOML != "" { b.WithSourceFile(filepath.Join("themes", name, "config.toml"), configTOML) } if themeTOML != "" { b.WithSourceFile(filepath.Join("themes", name, "theme.toml"), themeTOML) } } writeThemeFiles("n1", n1, "") writeThemeFiles("n2", n2, "") writeThemeFiles("n3", n3, "") writeThemeFiles("n4", n4, "") writeThemeFiles("o1", o1c, o1t) b.WithConfigFile("toml", ` [module] [[module.imports]] path="n1" [[module.imports]] path="n4" `) b.Build(BuildCfg{}) modulesClient := b.H.Paths.ModulesClient var graphb bytes.Buffer modulesClient.Graph(&graphb) assert.Equal(`project n1 n1 o1 o1 n2 n1 n3 project n4 `, graphb.String()) } func TestLoadConfigWithOsEnvOverrides(t *testing.T) { assert := require.New(t) baseConfig := ` environment = "production" enableGitInfo = true intSlice = [5,7,9] floatSlice = [3.14, 5.19] stringSlice = ["a", "b"] [imaging] anchor = "smart" quality = 75 resamplefilter = "CatmullRom" ` b := newTestSitesBuilder(t).WithConfigFile("toml", baseConfig) b.WithEnviron( "HUGO_ENVIRONMENT", "test", "HUGO_NEW", "new", // key not in config.toml "HUGO_ENABLEGITINFO", "false", "HUGO_IMAGING_ANCHOR", "top", "HUGO_STRINGSLICE", `["c", "d"]`, "HUGO_INTSLICE", `[5, 8, 9]`, "HUGO_FLOATSLICE", `[5.32]`, ) b.Build(BuildCfg{}) cfg := b.H.Cfg assert.Equal("test", cfg.Get("environment")) assert.Equal(false, cfg.GetBool("enablegitinfo")) assert.Equal("new", cfg.Get("new")) assert.Equal("top", cfg.Get("imaging.anchor")) assert.Equal(int64(75), cfg.Get("imaging.quality")) assert.Equal([]interface{}{"c", "d"}, cfg.Get("stringSlice")) assert.Equal([]interface{}{5.32}, cfg.Get("floatSlice")) assert.Equal([]interface{}{5, 8, 9}, cfg.Get("intSlice")) }