github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/tpl/tplimpl/template_ast_transformers_test.go (about) 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 package tplimpl 14 15 import ( 16 "bytes" 17 "testing" 18 19 "html/template" 20 21 "github.com/stretchr/testify/require" 22 ) 23 24 var ( 25 testFuncs = map[string]interface{}{ 26 "Echo": func(v interface{}) interface{} { return v }, 27 } 28 29 paramsData = map[string]interface{}{ 30 "NotParam": "Hi There", 31 "Slice": []int{1, 3}, 32 "Params": map[string]interface{}{ 33 "lower": "P1L", 34 }, 35 "Site": map[string]interface{}{ 36 "Params": map[string]interface{}{ 37 "lower": "P2L", 38 "slice": []int{1, 3}, 39 }, 40 "Language": map[string]interface{}{ 41 "Params": map[string]interface{}{ 42 "lower": "P22L", 43 }, 44 }, 45 "Data": map[string]interface{}{ 46 "Params": map[string]interface{}{ 47 "NOLOW": "P3H", 48 }, 49 }, 50 }, 51 } 52 53 paramsTempl = ` 54 {{ $page := . }} 55 {{ $pageParams := .Params }} 56 {{ $site := .Site }} 57 {{ $siteParams := .Site.Params }} 58 {{ $data := .Site.Data }} 59 {{ $notparam := .NotParam }} 60 61 P1: {{ .Params.LOWER }} 62 P1_2: {{ $.Params.LOWER }} 63 P1_3: {{ $page.Params.LOWER }} 64 P1_4: {{ $pageParams.LOWER }} 65 P2: {{ .Site.Params.LOWER }} 66 P2_2: {{ $.Site.Params.LOWER }} 67 P2_3: {{ $site.Params.LOWER }} 68 P2_4: {{ $siteParams.LOWER }} 69 P22: {{ .Site.Language.Params.LOWER }} 70 P3: {{ .Site.Data.Params.NOLOW }} 71 P3_2: {{ $.Site.Data.Params.NOLOW }} 72 P3_3: {{ $site.Data.Params.NOLOW }} 73 P3_4: {{ $data.Params.NOLOW }} 74 P4: {{ range $i, $e := .Site.Params.SLICE }}{{ $e }}{{ end }} 75 P5: {{ Echo .Params.LOWER }} 76 P5_2: {{ Echo $site.Params.LOWER }} 77 {{ if .Params.LOWER }} 78 IF: {{ .Params.LOWER }} 79 {{ end }} 80 {{ if .Params.NOT_EXIST }} 81 {{ else }} 82 ELSE: {{ .Params.LOWER }} 83 {{ end }} 84 85 86 {{ with .Params.LOWER }} 87 WITH: {{ . }} 88 {{ end }} 89 90 91 {{ range .Slice }} 92 RANGE: {{ . }}: {{ $.Params.LOWER }} 93 {{ end }} 94 {{ index .Slice 1 }} 95 {{ .NotParam }} 96 {{ .NotParam }} 97 {{ .NotParam }} 98 {{ .NotParam }} 99 {{ .NotParam }} 100 {{ .NotParam }} 101 {{ .NotParam }} 102 {{ .NotParam }} 103 {{ .NotParam }} 104 {{ .NotParam }} 105 {{ $notparam }} 106 107 108 {{ $lower := .Site.Params.LOWER }} 109 F1: {{ printf "themes/%s-theme" .Site.Params.LOWER }} 110 F2: {{ Echo (printf "themes/%s-theme" $lower) }} 111 F3: {{ Echo (printf "themes/%s-theme" .Site.Params.LOWER) }} 112 ` 113 ) 114 115 func TestParamsKeysToLower(t *testing.T) { 116 t.Parallel() 117 118 require.Error(t, applyTemplateTransformers(nil, nil)) 119 120 templ, err := template.New("foo").Funcs(testFuncs).Parse(paramsTempl) 121 122 require.NoError(t, err) 123 124 c := newTemplateContext(createParseTreeLookup(templ)) 125 126 require.Equal(t, -1, c.decl.indexOfReplacementStart([]string{})) 127 128 c.paramsKeysToLower(templ.Tree.Root) 129 130 var b bytes.Buffer 131 132 require.NoError(t, templ.Execute(&b, paramsData)) 133 134 result := b.String() 135 136 require.Contains(t, result, "P1: P1L") 137 require.Contains(t, result, "P1_2: P1L") 138 require.Contains(t, result, "P1_3: P1L") 139 require.Contains(t, result, "P1_4: P1L") 140 require.Contains(t, result, "P2: P2L") 141 require.Contains(t, result, "P2_2: P2L") 142 require.Contains(t, result, "P2_3: P2L") 143 require.Contains(t, result, "P2_4: P2L") 144 require.Contains(t, result, "P22: P22L") 145 require.Contains(t, result, "P3: P3H") 146 require.Contains(t, result, "P3_2: P3H") 147 require.Contains(t, result, "P3_3: P3H") 148 require.Contains(t, result, "P3_4: P3H") 149 require.Contains(t, result, "P4: 13") 150 require.Contains(t, result, "P5: P1L") 151 require.Contains(t, result, "P5_2: P2L") 152 153 require.Contains(t, result, "IF: P1L") 154 require.Contains(t, result, "ELSE: P1L") 155 156 require.Contains(t, result, "WITH: P1L") 157 158 require.Contains(t, result, "RANGE: 3: P1L") 159 160 require.Contains(t, result, "Hi There") 161 162 // Issue #2740 163 require.Contains(t, result, "F1: themes/P2L-theme") 164 require.Contains(t, result, "F2: themes/P2L-theme") 165 require.Contains(t, result, "F3: themes/P2L-theme") 166 167 } 168 169 func BenchmarkTemplateParamsKeysToLower(b *testing.B) { 170 templ, err := template.New("foo").Funcs(testFuncs).Parse(paramsTempl) 171 172 if err != nil { 173 b.Fatal(err) 174 } 175 176 templates := make([]*template.Template, b.N) 177 178 for i := 0; i < b.N; i++ { 179 templates[i], err = templ.Clone() 180 if err != nil { 181 b.Fatal(err) 182 } 183 } 184 185 b.ResetTimer() 186 187 for i := 0; i < b.N; i++ { 188 c := newTemplateContext(createParseTreeLookup(templates[i])) 189 c.paramsKeysToLower(templ.Tree.Root) 190 } 191 } 192 193 func TestParamsKeysToLowerVars(t *testing.T) { 194 t.Parallel() 195 var ( 196 ctx = map[string]interface{}{ 197 "Params": map[string]interface{}{ 198 "colors": map[string]interface{}{ 199 "blue": "Amber", 200 }, 201 }, 202 } 203 204 // This is how Amber behaves: 205 paramsTempl = ` 206 {{$__amber_1 := .Params.Colors}} 207 {{$__amber_2 := $__amber_1.Blue}} 208 Color: {{$__amber_2}} 209 Blue: {{ $__amber_1.Blue}} 210 ` 211 ) 212 213 templ, err := template.New("foo").Parse(paramsTempl) 214 215 require.NoError(t, err) 216 217 c := newTemplateContext(createParseTreeLookup(templ)) 218 219 c.paramsKeysToLower(templ.Tree.Root) 220 221 var b bytes.Buffer 222 223 require.NoError(t, templ.Execute(&b, ctx)) 224 225 result := b.String() 226 227 require.Contains(t, result, "Color: Amber") 228 229 } 230 231 func TestParamsKeysToLowerInBlockTemplate(t *testing.T) { 232 t.Parallel() 233 234 var ( 235 ctx = map[string]interface{}{ 236 "Params": map[string]interface{}{ 237 "lower": "P1L", 238 }, 239 } 240 241 master = ` 242 P1: {{ .Params.LOWER }} 243 {{ block "main" . }}DEFAULT{{ end }}` 244 overlay = ` 245 {{ define "main" }} 246 P2: {{ .Params.LOWER }} 247 {{ end }}` 248 ) 249 250 masterTpl, err := template.New("foo").Parse(master) 251 require.NoError(t, err) 252 253 overlayTpl, err := template.Must(masterTpl.Clone()).Parse(overlay) 254 require.NoError(t, err) 255 overlayTpl = overlayTpl.Lookup(overlayTpl.Name()) 256 257 c := newTemplateContext(createParseTreeLookup(overlayTpl)) 258 259 c.paramsKeysToLower(overlayTpl.Tree.Root) 260 261 var b bytes.Buffer 262 263 require.NoError(t, overlayTpl.Execute(&b, ctx)) 264 265 result := b.String() 266 267 require.Contains(t, result, "P1: P1L") 268 require.Contains(t, result, "P2: P1L") 269 } 270 271 // Issue #2927 272 func TestTransformRecursiveTemplate(t *testing.T) { 273 274 recursive := ` 275 {{ define "menu-nodes" }} 276 {{ template "menu-node" }} 277 {{ end }} 278 {{ define "menu-node" }} 279 {{ template "menu-node" }} 280 {{ end }} 281 {{ template "menu-nodes" }} 282 ` 283 284 templ, err := template.New("foo").Parse(recursive) 285 require.NoError(t, err) 286 287 c := newTemplateContext(createParseTreeLookup(templ)) 288 c.paramsKeysToLower(templ.Tree.Root) 289 290 }