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  }