summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-11-14 19:13:09 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-11-14 22:31:50 +0100
commitf6ab9553f4c0429586fc9221d1779c460cf4922a (patch)
tree0f4efed30fb9750b800a4865c5065285bbc4d1fc
parent58a98c7758f90a16df51e4fee9ead0233157a1e4 (diff)
tpl/internal: Sync go_templates
Closes #10411
-rw-r--r--scripts/fork_go_templates/main.go2
-rw-r--r--tpl/internal/go_templates/fmtsort/sort.go25
-rw-r--r--tpl/internal/go_templates/fmtsort/sort_test.go2
-rw-r--r--tpl/internal/go_templates/htmltemplate/clone_test.go5
-rw-r--r--tpl/internal/go_templates/htmltemplate/content_test.go6
-rw-r--r--tpl/internal/go_templates/htmltemplate/context.go4
-rw-r--r--tpl/internal/go_templates/htmltemplate/doc.go132
-rw-r--r--tpl/internal/go_templates/htmltemplate/error.go17
-rw-r--r--tpl/internal/go_templates/htmltemplate/escape.go12
-rw-r--r--tpl/internal/go_templates/htmltemplate/escape_test.go16
-rw-r--r--tpl/internal/go_templates/htmltemplate/exec_test.go52
-rw-r--r--tpl/internal/go_templates/htmltemplate/html.go12
-rw-r--r--tpl/internal/go_templates/htmltemplate/js_test.go3
-rw-r--r--tpl/internal/go_templates/htmltemplate/multi_test.go6
-rw-r--r--tpl/internal/go_templates/htmltemplate/template.go12
-rw-r--r--tpl/internal/go_templates/htmltemplate/template_test.go4
-rw-r--r--tpl/internal/go_templates/htmltemplate/url.go29
-rw-r--r--tpl/internal/go_templates/testenv/exec.go73
-rw-r--r--tpl/internal/go_templates/testenv/noopt.go12
-rw-r--r--tpl/internal/go_templates/testenv/opt.go12
-rw-r--r--tpl/internal/go_templates/testenv/testenv.go256
-rw-r--r--tpl/internal/go_templates/testenv/testenv_test.go54
-rw-r--r--tpl/internal/go_templates/testenv/testenv_unix.go2
-rw-r--r--tpl/internal/go_templates/texttemplate/doc.go5
-rw-r--r--tpl/internal/go_templates/texttemplate/exec.go26
-rw-r--r--tpl/internal/go_templates/texttemplate/exec_test.go54
-rw-r--r--tpl/internal/go_templates/texttemplate/funcs.go47
-rw-r--r--tpl/internal/go_templates/texttemplate/helper.go1
-rw-r--r--tpl/internal/go_templates/texttemplate/multi_test.go10
-rw-r--r--tpl/internal/go_templates/texttemplate/option.go2
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/lex.go250
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/lex_test.go61
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/parse.go42
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/parse_test.go9
34 files changed, 740 insertions, 515 deletions
diff --git a/scripts/fork_go_templates/main.go b/scripts/fork_go_templates/main.go
index 9296b7bdd..2f8516e8d 100644
--- a/scripts/fork_go_templates/main.go
+++ b/scripts/fork_go_templates/main.go
@@ -17,7 +17,7 @@ import (
)
func main() {
- // The current is built with 41a82aa9c3 text/template/parse: allow space after continue or break
+ // The current is built with be7068fb0804f661515c678bee9224b90b32869a text/template: correct assignment, not declaration, in range
fmt.Println("Forking ...")
defer fmt.Println("Done ...")
diff --git a/tpl/internal/go_templates/fmtsort/sort.go b/tpl/internal/go_templates/fmtsort/sort.go
index 34c1f477f..278a89bd7 100644
--- a/tpl/internal/go_templates/fmtsort/sort.go
+++ b/tpl/internal/go_templates/fmtsort/sort.go
@@ -36,19 +36,18 @@ func (o *SortedMap) Swap(i, j int) {
//
// The ordering rules are more general than with Go's < operator:
//
-// - when applicable, nil compares low
-// - ints, floats, and strings order by <
-// - NaN compares less than non-NaN floats
-// - bool compares false before true
-// - complex compares real, then imag
-// - pointers compare by machine address
-// - channel values compare by machine address
-// - structs compare each field in turn
-// - arrays compare each element in turn.
-// Otherwise identical arrays compare by length.
-// - interface values compare first by reflect.Type describing the concrete type
-// and then by concrete value as described in the previous rules.
-//
+// - when applicable, nil compares low
+// - ints, floats, and strings order by <
+// - NaN compares less than non-NaN floats
+// - bool compares false before true
+// - complex compares real, then imag
+// - pointers compare by machine address
+// - channel values compare by machine address
+// - structs compare each field in turn
+// - arrays compare each element in turn.
+// Otherwise identical arrays compare by length.
+// - interface values compare first by reflect.Type describing the concrete type
+// and then by concrete value as described in the previous rules.
func Sort(mapValue reflect.Value) *SortedMap {
if mapValue.Type().Kind() != reflect.Map {
return nil
diff --git a/tpl/internal/go_templates/fmtsort/sort_test.go b/tpl/internal/go_templates/fmtsort/sort_test.go
index a05e8a3c3..064b09107 100644
--- a/tpl/internal/go_templates/fmtsort/sort_test.go
+++ b/tpl/internal/go_templates/fmtsort/sort_test.go
@@ -147,7 +147,7 @@ func sprint(data any) string {
}
b.WriteString(sprintKey(key))
b.WriteRune(':')
- b.WriteString(fmt.Sprint(om.Value[i]))
+ fmt.Fprint(b, om.Value[i])
}
return b.String()
}
diff --git a/tpl/internal/go_templates/htmltemplate/clone_test.go b/tpl/internal/go_templates/htmltemplate/clone_test.go
index 553f656b5..7db335b5b 100644
--- a/tpl/internal/go_templates/htmltemplate/clone_test.go
+++ b/tpl/internal/go_templates/htmltemplate/clone_test.go
@@ -8,7 +8,6 @@
package template
import (
- "bytes"
"errors"
"fmt"
"io"
@@ -26,7 +25,7 @@ func TestAddParseTreeHTML(t *testing.T) {
t.Fatal(err)
}
added := Must(root.AddParseTree("b", tree["b"]))
- b := new(bytes.Buffer)
+ b := new(strings.Builder)
err = added.ExecuteTemplate(b, "a", "1>0")
if err != nil {
t.Fatal(err)
@@ -43,7 +42,7 @@ func TestClone(t *testing.T) {
// In the t2 template, it will be in a JavaScript context.
// In the t3 template, it will be in a CSS context.
const tmpl = `{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}`
- b := new(bytes.Buffer)
+ b := new(strings.Builder)
// Create an incomplete template t0.
t0 := Must(New("t0").Parse(tmpl))
diff --git a/tpl/internal/go_templates/htmltemplate/content_test.go b/tpl/internal/go_templates/htmltemplate/content_test.go
index 29221a4ad..fac4774cc 100644
--- a/tpl/internal/go_templates/htmltemplate/content_test.go
+++ b/tpl/internal/go_templates/htmltemplate/content_test.go
@@ -284,7 +284,7 @@ func TestTypedContent(t *testing.T) {
[]string{
`#ZgotmplZ`,
`#ZgotmplZ`,
- // Commas are not esacped
+ // Commas are not escaped.
`Hello,#ZgotmplZ`,
// Leading spaces are not percent escapes.
` dir=%22ltr%22`,
@@ -389,7 +389,7 @@ func TestTypedContent(t *testing.T) {
tmpl := Must(New("x").Parse(test.input))
pre := strings.Index(test.input, "{{.}}")
post := len(test.input) - (pre + 5)
- var b bytes.Buffer
+ var b strings.Builder
for i, x := range data {
b.Reset()
if err := tmpl.Execute(&b, x); err != nil {
@@ -423,7 +423,7 @@ func (s *errorer) Error() string {
func TestStringer(t *testing.T) {
s := &myStringer{3}
- b := new(bytes.Buffer)
+ b := new(strings.Builder)
tmpl := Must(New("x").Parse("{{.}}"))
if err := tmpl.Execute(b, s); err != nil {
t.Fatal(err)
diff --git a/tpl/internal/go_templates/htmltemplate/context.go b/tpl/internal/go_templates/htmltemplate/context.go
index c28e08dce..146a95d03 100644
--- a/tpl/internal/go_templates/htmltemplate/context.go
+++ b/tpl/internal/go_templates/htmltemplate/context.go
@@ -80,7 +80,9 @@ func (c context) mangle(templateName string) string {
// HTML5 parsing algorithm because a single token production in the HTML
// grammar may contain embedded actions in a template. For instance, the quoted
// HTML attribute produced by
-// <div title="Hello {{.World}}">
+//
+// <div title="Hello {{.World}}">
+//
// is a single token in HTML's grammar but in a template spans several nodes.
type state uint8
diff --git a/tpl/internal/go_templates/htmltemplate/doc.go b/tpl/internal/go_templates/htmltemplate/doc.go
index b6a1504f8..8422b4921 100644
--- a/tpl/internal/go_templates/htmltemplate/doc.go
+++ b/tpl/internal/go_templates/htmltemplate/doc.go
@@ -12,14 +12,14 @@ The documentation here focuses on the security features of the package.
For information about how to program the templates themselves, see the
documentation for text/template.
-Introduction
+# Introduction
This package wraps package text/template so you can share its template API
to parse and execute HTML templates safely.
- tmpl, err := template.New("name").Parse(...)
- // Error checking elided
- err = tmpl.Execute(out, data)
+ tmpl, err := template.New("name").Parse(...)
+ // Error checking elided
+ err = tmpl.Execute(out, data)
If successful, tmpl will now be injection-safe. Otherwise, err is an error
defined in the docs for ErrorCode.
@@ -34,38 +34,37 @@ provided below.
Example
- import template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
- ...
- t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
- err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
+ import template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
+ ...
+ t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
+ err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
produces
- Hello, <script>alert('you have been pwned')</script>!
+ Hello, <script>alert('you have been pwned')</script>!
but the contextual autoescaping in html/template
- import template "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"
- ...
- t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
- err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
+ import template "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"
+ ...
+ t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
+ err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
produces safe, escaped HTML output
- Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!
+ Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!
-
-Contexts
+# Contexts
This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing
functions to each simple action pipeline, so given the excerpt
- <a href="/search?q={{.}}">{{.}}</a>
+ <a href="/search?q={{.}}">{{.}}</a>
At parse time each {{.}} is overwritten to add escaping functions as necessary.
In this case it becomes
- <a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>
+ <a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>
where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping
functions.
@@ -73,117 +72,113 @@ functions.
For these internal escaping functions, if an action pipeline evaluates to
a nil interface value, it is treated as though it were an empty string.
-Namespaced and data- attributes
+# Namespaced and data- attributes
Attributes with a namespace are treated as if they had no namespace.
Given the excerpt
- <a my:href="{{.}}"></a>
+ <a my:href="{{.}}"></a>
At parse time the attribute will be treated as if it were just "href".
So at parse time the template becomes:
- <a my:href="{{. | urlescaper | attrescaper}}"></a>
+ <a my:href="{{. | urlescaper | attrescaper}}"></a>
Similarly to attributes with namespaces, attributes with a "data-" prefix are
treated as if they had no "data-" prefix. So given
- <a data-href="{{.}}"></a>
+ <a data-href="{{.}}"></a>
At parse time this becomes
- <a data-href="{{. | urlescaper | attrescaper}}"></a>
+ <a data-href="{{. | urlescaper | attrescaper}}"></a>
If an attribute has both a namespace and a "data-" prefix, only the namespace
will be removed when determining the context. For example
- <a my:data-href="{{.}}"></a>
+ <a my:data-href="{{.}}"></a>
This is handled as if "my:data-href" was just "data-href" and not "href" as
it would be if the "data-" prefix were to be ignored too. Thus at parse
time this becomes just
- <a my:data-href="{{. | attrescaper}}"></a>
+ <a my:data-href="{{. | attrescaper}}"></a>
As a special case, attributes with the namespace "xmlns" are always treated
as containing URLs. Given the excerpts
- <a xmlns:title="{{.}}"></a>
- <a xmlns:href="{{.}}"></a>
- <a xmlns:onclick="{{.}}"></a>
+ <a xmlns:title="{{.}}"></a>
+ <a xmlns:href="{{.}}"></a>
+ <a xmlns:onclick="{{.}}"></a>
At parse time they become:
- <a xmlns:title="{{. | urlescaper | attrescaper}}"></a>
- <a xmlns:href="{{. | urlescaper | attrescaper}}"></a>
- <a xmlns:onclick="{{. | urlescaper | attrescaper}}"></a>
+ <a xmlns:title="{{. | urlescaper | attrescaper}}"></a>
+ <a xmlns:href="{{. | urlescaper | attrescaper}}"></a>
+ <a xmlns:onclick="{{. | urlescaper | attrescaper}}"></a>
-Errors
+# Errors
See the documentation of ErrorCode for details.
-
-A fuller picture
+# A fuller picture
The rest of this package comment may be skipped on first reading; it includes
details necessary to understand escaping contexts and error messages. Most users
will not need to understand these details.
-
-Contexts
+# Contexts
Assuming {{.}} is `O'Reilly: How are <i>you</i>?`, the table below shows
how {{.}} appears when used in the context to the left.
- Context {{.}} After
- {{.}} O'Reilly: How are &lt;i&gt;you&lt;/i&gt;?
- <a title='{{.}}'> O&#39;Reilly: How are you?
- <a href="/{{.}}"> O&#39;Reilly: How are %3ci%3eyou%3c/i%3e?
- <a href="?q={{.}}"> O&#39;Reilly%3a%20How%20are%3ci%3e...%3f
- <a onx='f("{{.}}")'> O\x27Reilly: How are \x3ci\x3eyou...?
- <a onx='f({{.}})'> "O\x27Reilly: How are \x3ci\x3eyou...?"
- <a onx='pattern = /{{.}}/;'> O\x27Reilly: How are \x3ci\x3eyou...\x3f
+ Context {{.}} After
+ {{.}} O'Reilly: How are &lt;i&gt;you&lt;/i&gt;?
+ <a title='{{.}}'> O&#39;Reilly: How are you?
+ <a href="/{{.}}"> O&#39;Reilly: How are %3ci%3eyou%3c/i%3e?
+ <a href="?q={{.}}"> O&#39;Reilly%3a%20How%20are%3ci%3e...%3f
+ <a onx='f("{{.}}")'> O\x27Reilly: How are \x3ci\x3eyou...?
+ <a onx='f({{.}})'> "O\x27Reilly: How are \x3ci\x3eyou...?"
+ <a onx='pattern = /{{.}}/;'> O\x27Reilly: How are \x3ci\x3eyou...\x3f
If used in an unsafe context, then the value might be filtered out:
- Context {{.}} After
- <a href="{{.}}"> #ZgotmplZ
+ Context {{.}} After
+ <a href="{{.}}"> #ZgotmplZ
since "O'Reilly:" is not an allowed protocol like "http:".
-
If {{.}} is the innocuous word, `left`, then it can appear more widely,
- Context {{.}} After
- {{.}} left
- <a title='{{.}}'> left
- <a href='{{.}}'> left
- <a href='/{{.}}'> left
- <a href='?dir={{.}}'> left
- <a style="border-{{.}}: 4px"> left
- <a style="align: {{.}}"> left
- <a style="background: '{{.}}'> left
- <a style="background: url('{{.}}')> left
- <style>p.{{.}} {color:red}</style> left
+ Context {{.}} After
+ {{.}} left
+ <a title='{{.}}'> left
+ <a href='{{.}}'> left
+ <a href='/{{.}}'> left
+ <a href='?dir={{.}}'> left
+ <a style="border-{{.}}: 4px"> left
+ <a style="align: {{.}}"> left
+ <a style="background: '{{.}}'> left
+ <a style="background: url('{{.}}')> left
+ <style>p.{{.}} {color:red}</style> left
Non-string values can be used in JavaScript contexts.
If {{.}} is
- struct{A,B string}{ "foo", "bar" }
+ struct{A,B string}{ "foo", "bar" }
in the escaped template
- <script>var pair = {{.}};</script>
+ <script>var pair = {{.}};</script>
then the template output is
- <script>var pair = {"A": "foo", "B": "bar"};</script>
+ <script>var pair = {"A": "foo", "B": "bar"};</script>
See package json to understand how non-string content is marshaled for
embedding in JavaScript contexts.
-
-Typed Strings
+# Typed Strings
By default, this package assumes that all pipelines produce a plain text string.
It adds escaping pipeline stages necessary to correctly and safely embed that
@@ -197,24 +192,23 @@ exempted from escaping.
The template
- Hello, {{.}}!
+ Hello, {{.}}!
can be invoked with
- tmpl.Execute(out, template.HTML(`<b>World</b>`))
+ tmpl.Execute(out, template.HTML(`<b>World</b>`))
to produce
- Hello, <b>World</b>!
+ Hello, <b>World</b>!
instead of the
- Hello, &lt;b&gt;World&lt;b&gt;!
+ Hello, &lt;b&gt;World&lt;b&gt;!
that would have been produced if {{.}} was a regular string.
-
-Security Model
+# Security Model
https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
diff --git a/tpl/internal/go_templates/htmltemplate/error.go b/tpl/internal/go_templates/htmltemplate/error.go
index 21c86a9ef..916b41a82 100644
--- a/tpl/internal/go_templates/htmltemplate/error.go
+++ b/tpl/internal/go_templates/htmltemplate/error.go
@@ -33,14 +33,17 @@ type ErrorCode int
//
// Output: "ZgotmplZ"
// Example:
-// <img src="{{.X}}">
-// where {{.X}} evaluates to `javascript:...`
+//
+// <img src="{{.X}}">
+// where {{.X}} evaluates to `javascript:...`
+//
// Discussion:
-// "ZgotmplZ" is a special value that indicates that unsafe content reached a
-// CSS or URL context at runtime. The output of the example will be
-// <img src="#ZgotmplZ">
-// If the data comes from a trusted source, use content types to exempt it
-// from filtering: URL(`javascript:...`).
+//
+// "ZgotmplZ" is a special value that indicates that unsafe content reached a
+// CSS or URL context at runtime. The output of the example will be
+// <img src="#ZgotmplZ">
+// If the data comes from a trusted source, use content types to exempt it
+// from filtering: URL(`javascript:...`).
const (
// OK indicates the lack of an error.
OK ErrorCode = iota
diff --git a/tpl/internal/go_templates/htmltemplate/escape.go b/tpl/internal/go_templates/htmltemplate/escape.go
index 488894416..3aac865ef 100644
--- a/tpl/internal/go_templates/htmltemplate/escape.go
+++ b/tpl/internal/go_templates/htmltemplate/escape.go
@@ -412,13 +412,19 @@ func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode {
// nudge returns the context that would result from following empty string
// transitions from the input context.
// For example, parsing:
-// `<a href=`
+//
+// `<a href=`
+//
// will end in context{stateBeforeValue, attrURL}, but parsing one extra rune:
-// `<a href=x`
+//
+// `<a href=x`
+//
// will end in context{stateURL, delimSpaceOrTagEnd, ...}.
// There are two transitions that happen when the 'x' is seen:
// (1) Transition from a before-value state to a start-of-value state without
-// consuming any character.
+//
+// consuming any character.
+//
// (2) Consume 'x' and transition past the first value character.
// In this case, nudging produces the context after (1) happens.
func nudge(c context) context {
diff --git a/tpl/internal/go_templates/htmltemplate/escape_test.go b/tpl/internal/go_templates/htmltemplate/escape_test.go
index adf160b5d..a08ea57ef 100644
--- a/tpl/internal/go_templates/htmltemplate/escape_test.go
+++ b/tpl/internal/go_templates/htmltemplate/escape_test.go
@@ -693,7 +693,7 @@ func TestEscape(t *testing.T) {
t.Errorf("%s: tree not set properly", test.name)
continue
}
- b := new(bytes.Buffer)
+ b := new(strings.Builder)
if err := tmpl.Execute(b, data); err != nil {
t.Errorf("%s: template execution failed: %s", test.name, err)
continue
@@ -740,7 +740,7 @@ func TestEscapeMap(t *testing.T) {
},
} {
tmpl := Must(New("").Parse(test.input))
- b := new(bytes.Buffer)
+ b := new(strings.Builder)
if err := tmpl.Execute(b, data); err != nil {
t.Errorf("%s: template execution failed: %s", test.desc, err)
continue
@@ -882,7 +882,7 @@ func TestEscapeSet(t *testing.T) {
t.Errorf("error parsing %q: %v", source, err)
continue
}
- var b bytes.Buffer
+ var b strings.Builder
if err := tmpl.ExecuteTemplate(&b, "main", data); err != nil {
t.Errorf("%q executing %v", err.Error(), tmpl.Lookup("main"))
@@ -1833,7 +1833,7 @@ func TestIndirectPrint(t *testing.T) {
bp := &b
bpp := &bp
tmpl := Must(New("t").Parse(`{{.}}`))
- var buf bytes.Buffer
+ var buf strings.Builder
err := tmpl.Execute(&buf, ap)
if err != nil {
t.Errorf("Unexpected error: %s", err)
@@ -1876,7 +1876,7 @@ func TestPipeToMethodIsEscaped(t *testing.T) {
t.Errorf("panicked: %v\n", panicValue)
}
}()
- var b bytes.Buffer
+ var b strings.Builder
tmpl.Execute(&b, Issue7379(0))
return b.String()
}
@@ -1909,7 +1909,7 @@ func TestIdempotentExecute(t *testing.T) {
Parse(`{{define "main"}}<body>{{template "hello"}}</body>{{end}}`))
Must(tmpl.
Parse(`{{define "hello"}}Hello, {{"Ladies & Gentlemen!"}}{{end}}`))
- got := new(bytes.Buffer)
+ got := new(strings.Builder)
var err error
// Ensure that "hello" produces the same output when executed twice.
want := "Hello, Ladies &amp; Gentlemen!"
@@ -1952,7 +1952,7 @@ func TestOrphanedTemplate(t *testing.T) {
t1 := Must(New("foo").Parse(`<a href="{{.}}">link1</a>`))
t2 := Must(t1.New("foo").Parse(`bar`))
- var b bytes.Buffer
+ var b strings.Builder
const wantError = `template: "foo" is an incomplete or empty template`
if err := t1.Execute(&b, "javascript:alert(1)"); err == nil {
t.Fatal("expected error executing t1")
@@ -1981,7 +1981,7 @@ func TestAliasedParseTreeDoesNotOverescape(t *testing.T) {
if _, err := tpl.AddParseTree("bar", tpl.Tree); err != nil {
t.Fatalf("AddParseTree error: %v", err)
}
- var b1, b2 bytes.Buffer
+ var b1, b2 strings.Builder
if err := tpl.ExecuteTemplate(&b1, "foo", data); err != nil {
t.Fatalf(`ExecuteTemplate failed for "foo": %v`, err)
}
diff --git a/tpl/internal/go_templates/htmltemplate/exec_test.go b/tpl/internal/go_templates/htmltemplate/exec_test.go
index 08195af0e..0f29cb060 100644
--- a/tpl/internal/go_templates/htmltemplate/exec_test.go
+++ b/tpl/internal/go_templates/htmltemplate/exec_test.go
@@ -769,7 +769,7 @@ func mapOfThree() any {
}
func testExecute(execTests []execTest, template *Template, t *testing.T) {
- b := new(bytes.Buffer)
+ b := new(strings.Builder)
funcs := FuncMap{
"add": add,
"count": count,
@@ -861,7 +861,7 @@ func TestDelims(t *test