code.gitea.io/gitea@v1.22.3/modules/templates/scopedtmpl/scopedtmpl_test.go (about)

     1  // Copyright 2023 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package scopedtmpl
     5  
     6  import (
     7  	"bytes"
     8  	"html/template"
     9  	"strings"
    10  	"sync"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  func TestScopedTemplateSetFuncMap(t *testing.T) {
    18  	all := template.New("")
    19  
    20  	all.Funcs(template.FuncMap{"CtxFunc": func(s string) string {
    21  		return "default"
    22  	}})
    23  
    24  	_, err := all.New("base").Parse(`{{CtxFunc "base"}}`)
    25  	assert.NoError(t, err)
    26  
    27  	_, err = all.New("test").Parse(strings.TrimSpace(`
    28  {{template "base"}}
    29  {{CtxFunc "test"}}
    30  {{template "base"}}
    31  {{CtxFunc "test"}}
    32  `))
    33  	assert.NoError(t, err)
    34  
    35  	ts, err := newScopedTemplateSet(all, "test")
    36  	assert.NoError(t, err)
    37  
    38  	// try to use different CtxFunc to render concurrently
    39  
    40  	funcMap1 := template.FuncMap{
    41  		"CtxFunc": func(s string) string {
    42  			time.Sleep(100 * time.Millisecond)
    43  			return s + "1"
    44  		},
    45  	}
    46  
    47  	funcMap2 := template.FuncMap{
    48  		"CtxFunc": func(s string) string {
    49  			time.Sleep(100 * time.Millisecond)
    50  			return s + "2"
    51  		},
    52  	}
    53  
    54  	out1 := bytes.Buffer{}
    55  	out2 := bytes.Buffer{}
    56  	wg := sync.WaitGroup{}
    57  	wg.Add(2)
    58  	go func() {
    59  		err := ts.newExecutor(funcMap1).Execute(&out1, nil)
    60  		assert.NoError(t, err)
    61  		wg.Done()
    62  	}()
    63  	go func() {
    64  		err := ts.newExecutor(funcMap2).Execute(&out2, nil)
    65  		assert.NoError(t, err)
    66  		wg.Done()
    67  	}()
    68  	wg.Wait()
    69  	assert.Equal(t, "base1\ntest1\nbase1\ntest1", out1.String())
    70  	assert.Equal(t, "base2\ntest2\nbase2\ntest2", out2.String())
    71  }
    72  
    73  func TestScopedTemplateSetEscape(t *testing.T) {
    74  	all := template.New("")
    75  	_, err := all.New("base").Parse(`<a href="?q={{.param}}">{{.text}}</a>`)
    76  	assert.NoError(t, err)
    77  
    78  	_, err = all.New("test").Parse(`{{template "base" .}}<form action="?q={{.param}}">{{.text}}</form>`)
    79  	assert.NoError(t, err)
    80  
    81  	ts, err := newScopedTemplateSet(all, "test")
    82  	assert.NoError(t, err)
    83  
    84  	out := bytes.Buffer{}
    85  	err = ts.newExecutor(nil).Execute(&out, map[string]string{"param": "/", "text": "<"})
    86  	assert.NoError(t, err)
    87  
    88  	assert.Equal(t, `<a href="?q=%2f">&lt;</a><form action="?q=%2f">&lt;</form>`, out.String())
    89  }
    90  
    91  func TestScopedTemplateSetUnsafe(t *testing.T) {
    92  	all := template.New("")
    93  	_, err := all.New("test").Parse(`<a href="{{if true}}?{{end}}a={{.param}}"></a>`)
    94  	assert.NoError(t, err)
    95  
    96  	_, err = newScopedTemplateSet(all, "test")
    97  	assert.ErrorContains(t, err, "appears in an ambiguous context within a URL")
    98  }