1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 func TestAddParseTree(t
*testing
.T
) {
16 root
:= Must(New("root").Parse(`{{define "a"}} {{.}} {{template "b"}} {{.}} "></a>{{end}}`))
17 tree
, err
:= parse
.Parse("t", `{{define "b"}}<a href="{{end}}`, "", "", nil, nil)
21 added
:= Must(root
.AddParseTree("b", tree
["b"]))
22 b
:= new(bytes
.Buffer
)
23 err
= added
.ExecuteTemplate(b
, "a", "1>0")
27 if got
, want
:= b
.String(), ` 1>0 <a href=" 1%3e0 "></a>`; got
!= want
{
28 t
.Errorf("got %q want %q", got
, want
)
32 func TestClone(t
*testing
.T
) {
33 // The {{.}} will be executed with data "<i>*/" in different contexts.
34 // In the t0 template, it will be in a text context.
35 // In the t1 template, it will be in a URL context.
36 // In the t2 template, it will be in a JavaScript context.
37 // In the t3 template, it will be in a CSS context.
38 const tmpl
= `{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}`
39 b
:= new(bytes
.Buffer
)
41 // Create an incomplete template t0.
42 t0
:= Must(New("t0").Parse(tmpl
))
45 t1
:= Must(t0
.Clone())
46 Must(t1
.Parse(`{{define "lhs"}} <a href=" {{end}}`))
47 Must(t1
.Parse(`{{define "rhs"}} "></a> {{end}}`))
51 if err
:= t1
.ExecuteTemplate(b
, "a", "<i>*/"); err
!= nil {
54 if got
, want
:= b
.String(), ` <a href=" %3ci%3e*/ "></a> `; got
!= want
{
55 t
.Errorf("t1: got %q want %q", got
, want
)
59 t2
:= Must(t0
.Clone())
60 Must(t2
.Parse(`{{define "lhs"}} <p onclick="javascript: {{end}}`))
61 Must(t2
.Parse(`{{define "rhs"}} "></p> {{end}}`))
65 if err
:= t2
.ExecuteTemplate(b
, "a", "<i>*/"); err
!= nil {
68 if got
, want
:= b
.String(), ` <p onclick="javascript: "\u003ci\u003e*/" "></p> `; got
!= want
{
69 t
.Errorf("t2: got %q want %q", got
, want
)
72 // Clone t0 as t3, but do not execute t3 yet.
73 t3
:= Must(t0
.Clone())
74 Must(t3
.Parse(`{{define "lhs"}} <style> {{end}}`))
75 Must(t3
.Parse(`{{define "rhs"}} </style> {{end}}`))
78 Must(t0
.Parse(`{{define "lhs"}} ( {{end}}`))
79 Must(t0
.Parse(`{{define "rhs"}} ) {{end}}`))
81 // Clone t0 as t4. Redefining the "lhs" template should fail.
82 t4
:= Must(t0
.Clone())
83 if _
, err
:= t4
.Parse(`{{define "lhs"}} FAIL {{end}}`); err
== nil {
84 t
.Error(`redefine "lhs": got nil err want non-nil`)
89 if err
:= t0
.ExecuteTemplate(b
, "a", "<i>*/"); err
!= nil {
92 if got
, want
:= b
.String(), ` ( <i>*/ ) `; got
!= want
{
93 t
.Errorf("t0: got %q want %q", got
, want
)
96 // Clone t0. This should fail, as t0 has already executed.
97 if _
, err
:= t0
.Clone(); err
== nil {
98 t
.Error(`t0.Clone(): got nil err want non-nil`)
101 // Similarly, cloning sub-templates should fail.
102 if _
, err
:= t0
.Lookup("a").Clone(); err
== nil {
103 t
.Error(`t0.Lookup("a").Clone(): got nil err want non-nil`)
105 if _
, err
:= t0
.Lookup("lhs").Clone(); err
== nil {
106 t
.Error(`t0.Lookup("lhs").Clone(): got nil err want non-nil`)
111 if err
:= t3
.ExecuteTemplate(b
, "a", "<i>*/"); err
!= nil {
114 if got
, want
:= b
.String(), ` <style> ZgotmplZ </style> `; got
!= want
{
115 t
.Errorf("t3: got %q want %q", got
, want
)
119 func TestTemplates(t
*testing
.T
) {
120 names
:= []string{"t0", "a", "lhs", "rhs"}
121 // Some template definitions borrowed from TestClone.
123 {{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}
124 {{define "lhs"}} <a href=" {{end}}
125 {{define "rhs"}} "></a> {{end}}`
126 t0
:= Must(New("t0").Parse(tmpl
))
127 templates
:= t0
.Templates()
128 if len(templates
) != len(names
) {
129 t
.Errorf("expected %d templates; got %d", len(names
), len(templates
))
131 for _
, name
:= range names
{
133 for _
, tmpl
:= range templates
{
134 if name
== tmpl
.text
.Name() {
140 t
.Error("could not find template", name
)
145 // This used to crash; http://golang.org/issue/3281
146 func TestCloneCrash(t
*testing
.T
) {
148 Must(t1
.New("t1").Parse(`{{define "foo"}}foo{{end}}`))
152 // Ensure that this guarantee from the docs is upheld:
153 // "Further calls to Parse in the copy will add templates
154 // to the copy but not to the original."
155 func TestCloneThenParse(t
*testing
.T
) {
156 t0
:= Must(New("t0").Parse(`{{define "a"}}{{template "embedded"}}{{end}}`))
157 t1
:= Must(t0
.Clone())
158 Must(t1
.Parse(`{{define "embedded"}}t1{{end}}`))
159 if len(t0
.Templates())+1 != len(t1
.Templates()) {
160 t
.Error("adding a template to a clone added it to the original")
162 // double check that the embedded template isn't available in the original
163 err
:= t0
.ExecuteTemplate(ioutil
.Discard
, "a", nil)
165 t
.Error("expected 'no such template' error")
169 // https://code.google.com/p/go/issues/detail?id=5980
170 func TestFuncMapWorksAfterClone(t
*testing
.T
) {
171 funcs
:= FuncMap
{"customFunc": func() (string, error
) {
172 return "", errors
.New("issue5980")
175 // get the expected error output (no clone)
176 uncloned
:= Must(New("").Funcs(funcs
).Parse("{{customFunc}}"))
177 wantErr
:= uncloned
.Execute(ioutil
.Discard
, nil)
179 // toClone must be the same as uncloned. It has to be recreated from scratch,
180 // since cloning cannot occur after execution.
181 toClone
:= Must(New("").Funcs(funcs
).Parse("{{customFunc}}"))
182 cloned
:= Must(toClone
.Clone())
183 gotErr
:= cloned
.Execute(ioutil
.Discard
, nil)
185 if wantErr
.Error() != gotErr
.Error() {
186 t
.Errorf("clone error message mismatch want %q got %q", wantErr
, gotErr
)