1
2
3
4
5 package template
6
7
8
9 import (
10 "bytes"
11 "fmt"
12 "testing"
13 "text/template/parse"
14 )
15
16 const (
17 noError = true
18 hasError = false
19 )
20
21 type multiParseTest struct {
22 name string
23 input string
24 ok bool
25 names []string
26 results []string
27 }
28
29 var multiParseTests = []multiParseTest{
30 {"empty", "", noError,
31 nil,
32 nil},
33 {"one", `{{define "foo"}} FOO {{end}}`, noError,
34 []string{"foo"},
35 []string{" FOO "}},
36 {"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
37 []string{"foo", "bar"},
38 []string{" FOO ", " BAR "}},
39
40 {"missing end", `{{define "foo"}} FOO `, hasError,
41 nil,
42 nil},
43 {"malformed name", `{{define "foo}} FOO `, hasError,
44 nil,
45 nil},
46 }
47
48 func TestMultiParse(t *testing.T) {
49 for _, test := range multiParseTests {
50 template, err := New("root").Parse(test.input)
51 switch {
52 case err == nil && !test.ok:
53 t.Errorf("%q: expected error; got none", test.name)
54 continue
55 case err != nil && test.ok:
56 t.Errorf("%q: unexpected error: %v", test.name, err)
57 continue
58 case err != nil && !test.ok:
59
60 if *debug {
61 fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
62 }
63 continue
64 }
65 if template == nil {
66 continue
67 }
68 if len(template.tmpl) != len(test.names)+1 {
69 t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(template.tmpl))
70 continue
71 }
72 for i, name := range test.names {
73 tmpl, ok := template.tmpl[name]
74 if !ok {
75 t.Errorf("%s: can't find template %q", test.name, name)
76 continue
77 }
78 result := tmpl.Root.String()
79 if result != test.results[i] {
80 t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
81 }
82 }
83 }
84 }
85
86 var multiExecTests = []execTest{
87 {"empty", "", "", nil, true},
88 {"text", "some text", "some text", nil, true},
89 {"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
90 {"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
91 {"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
92 {"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
93 {"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
94 {"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
95 {"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
96
97
98 {"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
99 {"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
100 }
101
102
103 const multiText1 = `
104 {{define "x"}}TEXT{{end}}
105 {{define "dotV"}}{{.V}}{{end}}
106 `
107
108 const multiText2 = `
109 {{define "dot"}}{{.}}{{end}}
110 {{define "nested"}}{{template "dot" .}}{{end}}
111 `
112
113 func TestMultiExecute(t *testing.T) {
114
115 template, err := New("root").Parse(multiText1)
116 if err != nil {
117 t.Fatalf("parse error for 1: %s", err)
118 }
119 _, err = template.Parse(multiText2)
120 if err != nil {
121 t.Fatalf("parse error for 2: %s", err)
122 }
123 testExecute(multiExecTests, template, t)
124 }
125
126 func TestParseFiles(t *testing.T) {
127 _, err := ParseFiles("DOES NOT EXIST")
128 if err == nil {
129 t.Error("expected error for non-existent file; got none")
130 }
131 template := New("root")
132 _, err = template.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
133 if err != nil {
134 t.Fatalf("error parsing files: %v", err)
135 }
136 testExecute(multiExecTests, template, t)
137 }
138
139 func TestParseGlob(t *testing.T) {
140 _, err := ParseGlob("DOES NOT EXIST")
141 if err == nil {
142 t.Error("expected error for non-existent file; got none")
143 }
144 _, err = New("error").ParseGlob("[x")
145 if err == nil {
146 t.Error("expected error for bad pattern; got none")
147 }
148 template := New("root")
149 _, err = template.ParseGlob("testdata/file*.tmpl")
150 if err != nil {
151 t.Fatalf("error parsing files: %v", err)
152 }
153 testExecute(multiExecTests, template, t)
154 }
155
156
157
158 var templateFileExecTests = []execTest{
159 {"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true},
160 }
161
162 func TestParseFilesWithData(t *testing.T) {
163 template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
164 if err != nil {
165 t.Fatalf("error parsing files: %v", err)
166 }
167 testExecute(templateFileExecTests, template, t)
168 }
169
170 func TestParseGlobWithData(t *testing.T) {
171 template, err := New("root").ParseGlob("testdata/tmpl*.tmpl")
172 if err != nil {
173 t.Fatalf("error parsing files: %v", err)
174 }
175 testExecute(templateFileExecTests, template, t)
176 }
177
178 const (
179 cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}`
180 cloneText2 = `{{define "b"}}b{{end}}`
181 cloneText3 = `{{define "c"}}root{{end}}`
182 cloneText4 = `{{define "c"}}clone{{end}}`
183 )
184
185 func TestClone(t *testing.T) {
186
187 root, err := New("root").Parse(cloneText1)
188 if err != nil {
189 t.Fatal(err)
190 }
191 _, err = root.Parse(cloneText2)
192 if err != nil {
193 t.Fatal(err)
194 }
195 clone := Must(root.Clone())
196
197 _, err = root.Parse(cloneText3)
198 if err != nil {
199 t.Fatal(err)
200 }
201 _, err = clone.Parse(cloneText4)
202 if err != nil {
203 t.Fatal(err)
204 }
205
206 for k, v := range clone.tmpl {
207 if k == clone.name && v.tmpl[k] != clone {
208 t.Error("clone does not contain root")
209 }
210 if v != v.tmpl[v.name] {
211 t.Errorf("clone does not contain self for %q", k)
212 }
213 }
214
215 var b bytes.Buffer
216 err = root.ExecuteTemplate(&b, "a", 0)
217 if err != nil {
218 t.Fatal(err)
219 }
220 if b.String() != "broot" {
221 t.Errorf("expected %q got %q", "broot", b.String())
222 }
223
224 b.Reset()
225 err = clone.ExecuteTemplate(&b, "a", 0)
226 if err != nil {
227 t.Fatal(err)
228 }
229 if b.String() != "bclone" {
230 t.Errorf("expected %q got %q", "bclone", b.String())
231 }
232 }
233
234 func TestAddParseTree(t *testing.T) {
235
236 root, err := New("root").Parse(cloneText1)
237 if err != nil {
238 t.Fatal(err)
239 }
240 _, err = root.Parse(cloneText2)
241 if err != nil {
242 t.Fatal(err)
243 }
244
245 tree, err := parse.Parse("cloneText3", cloneText3, "", "", nil, builtins())
246 if err != nil {
247 t.Fatal(err)
248 }
249 added, err := root.AddParseTree("c", tree["c"])
250 if err != nil {
251 t.Fatal(err)
252 }
253
254 var b bytes.Buffer
255 err = added.ExecuteTemplate(&b, "a", 0)
256 if err != nil {
257 t.Fatal(err)
258 }
259 if b.String() != "broot" {
260 t.Errorf("expected %q got %q", "broot", b.String())
261 }
262 }
263
264
265 func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
266 master := "{{define \"master\"}}{{end}}"
267 tmpl := New("master")
268 tree, err := parse.Parse("master", master, "", "", nil)
269 if err != nil {
270 t.Fatalf("unexpected parse err: %v", err)
271 }
272 masterTree := tree["master"]
273 tmpl.AddParseTree("master", masterTree)
274 }
275
276 func TestRedefinition(t *testing.T) {
277 var tmpl *Template
278 var err error
279 if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
280 t.Fatalf("parse 1: %v", err)
281 }
282 if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err != nil {
283 t.Fatalf("got error %v, expected nil", err)
284 }
285 if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err != nil {
286 t.Fatalf("got error %v, expected nil", err)
287 }
288 }
289
290
291 func TestEmptyTemplateCloneCrash(t *testing.T) {
292 t1 := New("base")
293 t1.Clone()
294 }
295
296
297 func TestTemplateLookUp(t *testing.T) {
298 t1 := New("foo")
299 if t1.Lookup("foo") != nil {
300 t.Error("Lookup returned non-nil value for undefined template foo")
301 }
302 t1.New("bar")
303 if t1.Lookup("bar") != nil {
304 t.Error("Lookup returned non-nil value for undefined template bar")
305 }
306 t1.Parse(`{{define "foo"}}test{{end}}`)
307 if t1.Lookup("foo") == nil {
308 t.Error("Lookup returned nil value for defined template")
309 }
310 }
311
312 func TestNew(t *testing.T) {
313
314 t1, _ := New("test").Parse(`{{define "test"}}foo{{end}}`)
315 t2 := t1.New("test")
316
317 if t1.common != t2.common {
318 t.Errorf("t1 & t2 didn't share common struct; got %v != %v", t1.common, t2.common)
319 }
320 if t1.Tree == nil {
321 t.Error("defined template got nil Tree")
322 }
323 if t2.Tree != nil {
324 t.Error("undefined template got non-nil Tree")
325 }
326
327 containsT1 := false
328 for _, tmpl := range t1.Templates() {
329 if tmpl == t2 {
330 t.Error("Templates included undefined template")
331 }
332 if tmpl == t1 {
333 containsT1 = true
334 }
335 }
336 if !containsT1 {
337 t.Error("Templates didn't include defined template")
338 }
339 }
340
341 func TestParse(t *testing.T) {
342
343
344 t1 := New("test")
345 if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
346 t.Fatalf("parsing test: %s", err)
347 }
348 if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil {
349 t.Fatalf("parsing test: %s", err)
350 }
351 if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
352 t.Fatalf("parsing test: %s", err)
353 }
354 }
355
356 func TestEmptyTemplate(t *testing.T) {
357 cases := []struct {
358 defn []string
359 in string
360 want string
361 }{
362 {[]string{"x", "y"}, "", "y"},
363 {[]string{""}, "once", ""},
364 {[]string{"", ""}, "twice", ""},
365 {[]string{"{{.}}", "{{.}}"}, "twice", "twice"},
366 {[]string{"{{/* a comment */}}", "{{/* a comment */}}"}, "comment", ""},
367 {[]string{"{{.}}", ""}, "twice", ""},
368 }
369
370 for i, c := range cases {
371 root := New("root")
372
373 var (
374 m *Template
375 err error
376 )
377 for _, d := range c.defn {
378 m, err = root.New(c.in).Parse(d)
379 if err != nil {
380 t.Fatal(err)
381 }
382 }
383 buf := &bytes.Buffer{}
384 if err := m.Execute(buf, c.in); err != nil {
385 t.Error(i, err)
386 continue
387 }
388 if buf.String() != c.want {
389 t.Errorf("expected string %q: got %q", c.want, buf.String())
390 }
391 }
392 }
393
394
395
396
397 func TestIssue19294(t *testing.T) {
398
399
400
401
402 var inlined = map[string]string{
403 "stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`,
404 "xhtml": `{{block "stylesheet" .}}{{end}}`,
405 }
406 all := []string{"stylesheet", "xhtml"}
407 for i := 0; i < 100; i++ {
408 res, err := New("title.xhtml").Parse(`{{template "xhtml" .}}`)
409 if err != nil {
410 t.Fatal(err)
411 }
412 for _, name := range all {
413 _, err := res.New(name).Parse(inlined[name])
414 if err != nil {
415 t.Fatal(err)
416 }
417 }
418 var buf bytes.Buffer
419 res.Execute(&buf, 0)
420 if buf.String() != "stylesheet" {
421 t.Fatalf("iteration %d: got %q; expected %q", i, buf.String(), "stylesheet")
422 }
423 }
424 }
425
View as plain text