github.com/gohugoio/hugo@v0.88.1/tpl/tplimpl/template_funcs_test.go (about) 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 tplimpl 15 16 import ( 17 "bytes" 18 "fmt" 19 "path/filepath" 20 "reflect" 21 "testing" 22 "time" 23 24 "github.com/gohugoio/hugo/modules" 25 26 "github.com/gohugoio/hugo/resources/page" 27 28 qt "github.com/frankban/quicktest" 29 "github.com/gohugoio/hugo/common/hugo" 30 "github.com/gohugoio/hugo/common/loggers" 31 "github.com/gohugoio/hugo/config" 32 "github.com/gohugoio/hugo/deps" 33 "github.com/gohugoio/hugo/hugofs" 34 "github.com/gohugoio/hugo/langs" 35 "github.com/gohugoio/hugo/langs/i18n" 36 "github.com/gohugoio/hugo/tpl" 37 "github.com/gohugoio/hugo/tpl/internal" 38 "github.com/gohugoio/hugo/tpl/partials" 39 "github.com/spf13/afero" 40 41 ) 42 43 var logger = loggers.NewErrorLogger() 44 45 func newTestConfig() config.Provider { 46 v := config.New() 47 v.Set("contentDir", "content") 48 v.Set("dataDir", "data") 49 v.Set("i18nDir", "i18n") 50 v.Set("layoutDir", "layouts") 51 v.Set("archetypeDir", "archetypes") 52 v.Set("assetDir", "assets") 53 v.Set("resourceDir", "resources") 54 v.Set("publishDir", "public") 55 56 langs.LoadLanguageSettings(v, nil) 57 mod, err := modules.CreateProjectModule(v) 58 if err != nil { 59 panic(err) 60 } 61 v.Set("allModules", modules.Modules{mod}) 62 63 return v 64 } 65 66 func newDepsConfig(cfg config.Provider) deps.DepsCfg { 67 l := langs.NewLanguage("en", cfg) 68 return deps.DepsCfg{ 69 Language: l, 70 Site: page.NewDummyHugoSite(cfg), 71 Cfg: cfg, 72 Fs: hugofs.NewMem(l), 73 Logger: logger, 74 TemplateProvider: DefaultTemplateProvider, 75 TranslationProvider: i18n.NewTranslationProvider(), 76 } 77 } 78 79 func TestTemplateFuncsExamples(t *testing.T) { 80 t.Parallel() 81 c := qt.New(t) 82 83 workingDir := "/home/hugo" 84 85 v := newTestConfig() 86 87 v.Set("workingDir", workingDir) 88 v.Set("multilingual", true) 89 v.Set("contentDir", "content") 90 v.Set("assetDir", "assets") 91 v.Set("baseURL", "http://mysite.com/hugo/") 92 v.Set("CurrentContentLanguage", langs.NewLanguage("en", v)) 93 94 fs := hugofs.NewMem(v) 95 96 afero.WriteFile(fs.Source, filepath.Join(workingDir, "files", "README.txt"), []byte("Hugo Rocks!"), 0755) 97 98 depsCfg := newDepsConfig(v) 99 depsCfg.Fs = fs 100 d, err := deps.New(depsCfg) 101 defer d.Close() 102 c.Assert(err, qt.IsNil) 103 104 var data struct { 105 Title string 106 Section string 107 Hugo map[string]interface{} 108 Params map[string]interface{} 109 } 110 111 data.Title = "**BatMan**" 112 data.Section = "blog" 113 data.Params = map[string]interface{}{"langCode": "en"} 114 data.Hugo = map[string]interface{}{"Version": hugo.MustParseVersion("0.36.1").Version()} 115 116 for _, nsf := range internal.TemplateFuncsNamespaceRegistry { 117 ns := nsf(d) 118 for _, mm := range ns.MethodMappings { 119 for i, example := range mm.Examples { 120 in, expected := example[0], example[1] 121 d.WithTemplate = func(templ tpl.TemplateManager) error { 122 c.Assert(templ.AddTemplate("test", in), qt.IsNil) 123 c.Assert(templ.AddTemplate("partials/header.html", "<title>Hugo Rocks!</title>"), qt.IsNil) 124 return nil 125 } 126 c.Assert(d.LoadResources(), qt.IsNil) 127 128 var b bytes.Buffer 129 templ, _ := d.Tmpl().Lookup("test") 130 c.Assert(d.Tmpl().Execute(templ, &b, &data), qt.IsNil) 131 if b.String() != expected { 132 t.Fatalf("%s[%d]: got %q expected %q", ns.Name, i, b.String(), expected) 133 } 134 } 135 } 136 } 137 } 138 139 // TODO(bep) it would be dandy to put this one into the partials package, but 140 // we have some package cycle issues to solve first. 141 func TestPartialCached(t *testing.T) { 142 t.Parallel() 143 144 c := qt.New(t) 145 146 partial := `Now: {{ now.UnixNano }}` 147 name := "testing" 148 149 var data struct { 150 } 151 152 v := newTestConfig() 153 154 config := newDepsConfig(v) 155 156 config.WithTemplate = func(templ tpl.TemplateManager) error { 157 err := templ.AddTemplate("partials/"+name, partial) 158 if err != nil { 159 return err 160 } 161 162 return nil 163 } 164 165 de, err := deps.New(config) 166 c.Assert(err, qt.IsNil) 167 defer de.Close() 168 c.Assert(de.LoadResources(), qt.IsNil) 169 170 ns := partials.New(de) 171 172 res1, err := ns.IncludeCached(name, &data) 173 c.Assert(err, qt.IsNil) 174 175 for j := 0; j < 10; j++ { 176 time.Sleep(2 * time.Nanosecond) 177 res2, err := ns.IncludeCached(name, &data) 178 c.Assert(err, qt.IsNil) 179 180 if !reflect.DeepEqual(res1, res2) { 181 t.Fatalf("cache mismatch") 182 } 183 184 res3, err := ns.IncludeCached(name, &data, fmt.Sprintf("variant%d", j)) 185 c.Assert(err, qt.IsNil) 186 187 if reflect.DeepEqual(res1, res3) { 188 t.Fatalf("cache mismatch") 189 } 190 } 191 } 192 193 func BenchmarkPartial(b *testing.B) { 194 doBenchmarkPartial(b, func(ns *partials.Namespace) error { 195 _, err := ns.Include("bench1") 196 return err 197 }) 198 } 199 200 func BenchmarkPartialCached(b *testing.B) { 201 doBenchmarkPartial(b, func(ns *partials.Namespace) error { 202 _, err := ns.IncludeCached("bench1", nil) 203 return err 204 }) 205 } 206 207 func doBenchmarkPartial(b *testing.B, f func(ns *partials.Namespace) error) { 208 c := qt.New(b) 209 config := newDepsConfig(config.New()) 210 config.WithTemplate = func(templ tpl.TemplateManager) error { 211 err := templ.AddTemplate("partials/bench1", `{{ shuffle (seq 1 10) }}`) 212 if err != nil { 213 return err 214 } 215 216 return nil 217 } 218 219 de, err := deps.New(config) 220 c.Assert(err, qt.IsNil) 221 defer de.Close() 222 c.Assert(de.LoadResources(), qt.IsNil) 223 224 ns := partials.New(de) 225 226 b.ResetTimer() 227 b.RunParallel(func(pb *testing.PB) { 228 for pb.Next() { 229 if err := f(ns); err != nil { 230 b.Fatalf("error executing template: %s", err) 231 } 232 } 233 }) 234 }