Home | History | Annotate | Download | only in template
      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.
      4 
      5 package template
      6 
      7 // Tests for mulitple-template parsing and execution.
      8 
      9 import (
     10 	"bytes"
     11 	"fmt"
     12 	"strings"
     13 	"testing"
     14 	"text/template/parse"
     15 )
     16 
     17 const (
     18 	noError  = true
     19 	hasError = false
     20 )
     21 
     22 type multiParseTest struct {
     23 	name    string
     24 	input   string
     25 	ok      bool
     26 	names   []string
     27 	results []string
     28 }
     29 
     30 var multiParseTests = []multiParseTest{
     31 	{"empty", "", noError,
     32 		nil,
     33 		nil},
     34 	{"one", `{{define "foo"}} FOO {{end}}`, noError,
     35 		[]string{"foo"},
     36 		[]string{" FOO "}},
     37 	{"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
     38 		[]string{"foo", "bar"},
     39 		[]string{" FOO ", " BAR "}},
     40 	// errors
     41 	{"missing end", `{{define "foo"}} FOO `, hasError,
     42 		nil,
     43 		nil},
     44 	{"malformed name", `{{define "foo}} FOO `, hasError,
     45 		nil,
     46 		nil},
     47 }
     48 
     49 func TestMultiParse(t *testing.T) {
     50 	for _, test := range multiParseTests {
     51 		template, err := New("root").Parse(test.input)
     52 		switch {
     53 		case err == nil && !test.ok:
     54 			t.Errorf("%q: expected error; got none", test.name)
     55 			continue
     56 		case err != nil && test.ok:
     57 			t.Errorf("%q: unexpected error: %v", test.name, err)
     58 			continue
     59 		case err != nil && !test.ok:
     60 			// expected error, got one
     61 			if *debug {
     62 				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
     63 			}
     64 			continue
     65 		}
     66 		if template == nil {
     67 			continue
     68 		}
     69 		if len(template.tmpl) != len(test.names)+1 { // +1 for root
     70 			t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(template.tmpl))
     71 			continue
     72 		}
     73 		for i, name := range test.names {
     74 			tmpl, ok := template.tmpl[name]
     75 			if !ok {
     76 				t.Errorf("%s: can't find template %q", test.name, name)
     77 				continue
     78 			}
     79 			result := tmpl.Root.String()
     80 			if result != test.results[i] {
     81 				t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
     82 			}
     83 		}
     84 	}
     85 }
     86 
     87 var multiExecTests = []execTest{
     88 	{"empty", "", "", nil, true},
     89 	{"text", "some text", "some text", nil, true},
     90 	{"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
     91 	{"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
     92 	{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
     93 	{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
     94 	{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
     95 	{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
     96 	{"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
     97 
     98 	// User-defined function: test argument evaluator.
     99 	{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
    100 	{"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
    101 }
    102 
    103 // These strings are also in testdata/*.
    104 const multiText1 = `
    105 	{{define "x"}}TEXT{{end}}
    106 	{{define "dotV"}}{{.V}}{{end}}
    107 `
    108 
    109 const multiText2 = `
    110 	{{define "dot"}}{{.}}{{end}}
    111 	{{define "nested"}}{{template "dot" .}}{{end}}
    112 `
    113 
    114 func TestMultiExecute(t *testing.T) {
    115 	// Declare a couple of templates first.
    116 	template, err := New("root").Parse(multiText1)
    117 	if err != nil {
    118 		t.Fatalf("parse error for 1: %s", err)
    119 	}
    120 	_, err = template.Parse(multiText2)
    121 	if err != nil {
    122 		t.Fatalf("parse error for 2: %s", err)
    123 	}
    124 	testExecute(multiExecTests, template, t)
    125 }
    126 
    127 func TestParseFiles(t *testing.T) {
    128 	_, err := ParseFiles("DOES NOT EXIST")
    129 	if err == nil {
    130 		t.Error("expected error for non-existent file; got none")
    131 	}
    132 	template := New("root")
    133 	_, err = template.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
    134 	if err != nil {
    135 		t.Fatalf("error parsing files: %v", err)
    136 	}
    137 	testExecute(multiExecTests, template, t)
    138 }
    139 
    140 func TestParseGlob(t *testing.T) {
    141 	_, err := ParseGlob("DOES NOT EXIST")
    142 	if err == nil {
    143 		t.Error("expected error for non-existent file; got none")
    144 	}
    145 	_, err = New("error").ParseGlob("[x")
    146 	if err == nil {
    147 		t.Error("expected error for bad pattern; got none")
    148 	}
    149 	template := New("root")
    150 	_, err = template.ParseGlob("testdata/file*.tmpl")
    151 	if err != nil {
    152 		t.Fatalf("error parsing files: %v", err)
    153 	}
    154 	testExecute(multiExecTests, template, t)
    155 }
    156 
    157 // In these tests, actual content (not just template definitions) comes from the parsed files.
    158 
    159 var templateFileExecTests = []execTest{
    160 	{"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true},
    161 }
    162 
    163 func TestParseFilesWithData(t *testing.T) {
    164 	template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
    165 	if err != nil {
    166 		t.Fatalf("error parsing files: %v", err)
    167 	}
    168 	testExecute(templateFileExecTests, template, t)
    169 }
    170 
    171 func TestParseGlobWithData(t *testing.T) {
    172 	template, err := New("root").ParseGlob("testdata/tmpl*.tmpl")
    173 	if err != nil {
    174 		t.Fatalf("error parsing files: %v", err)
    175 	}
    176 	testExecute(templateFileExecTests, template, t)
    177 }
    178 
    179 const (
    180 	cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}`
    181 	cloneText2 = `{{define "b"}}b{{end}}`
    182 	cloneText3 = `{{define "c"}}root{{end}}`
    183 	cloneText4 = `{{define "c"}}clone{{end}}`
    184 )
    185 
    186 func TestClone(t *testing.T) {
    187 	// Create some templates and clone the root.
    188 	root, err := New("root").Parse(cloneText1)
    189 	if err != nil {
    190 		t.Fatal(err)
    191 	}
    192 	_, err = root.Parse(cloneText2)
    193 	if err != nil {
    194 		t.Fatal(err)
    195 	}
    196 	clone := Must(root.Clone())
    197 	// Add variants to both.
    198 	_, err = root.Parse(cloneText3)
    199 	if err != nil {
    200 		t.Fatal(err)
    201 	}
    202 	_, err = clone.Parse(cloneText4)
    203 	if err != nil {
    204 		t.Fatal(err)
    205 	}
    206 	// Verify that the clone is self-consistent.
    207 	for k, v := range clone.tmpl {
    208 		if k == clone.name && v.tmpl[k] != clone {
    209 			t.Error("clone does not contain root")
    210 		}
    211 		if v != v.tmpl[v.name] {
    212 			t.Errorf("clone does not contain self for %q", k)
    213 		}
    214 	}
    215 	// Execute root.
    216 	var b bytes.Buffer
    217 	err = root.ExecuteTemplate(&b, "a", 0)
    218 	if err != nil {
    219 		t.Fatal(err)
    220 	}
    221 	if b.String() != "broot" {
    222 		t.Errorf("expected %q got %q", "broot", b.String())
    223 	}
    224 	// Execute copy.
    225 	b.Reset()
    226 	err = clone.ExecuteTemplate(&b, "a", 0)
    227 	if err != nil {
    228 		t.Fatal(err)
    229 	}
    230 	if b.String() != "bclone" {
    231 		t.Errorf("expected %q got %q", "bclone", b.String())
    232 	}
    233 }
    234 
    235 func TestAddParseTree(t *testing.T) {
    236 	// Create some templates.
    237 	root, err := New("root").Parse(cloneText1)
    238 	if err != nil {
    239 		t.Fatal(err)
    240 	}
    241 	_, err = root.Parse(cloneText2)
    242 	if err != nil {
    243 		t.Fatal(err)
    244 	}
    245 	// Add a new parse tree.
    246 	tree, err := parse.Parse("cloneText3", cloneText3, "", "", nil, builtins)
    247 	if err != nil {
    248 		t.Fatal(err)
    249 	}
    250 	added, err := root.AddParseTree("c", tree["c"])
    251 	// Execute.
    252 	var b bytes.Buffer
    253 	err = added.ExecuteTemplate(&b, "a", 0)
    254 	if err != nil {
    255 		t.Fatal(err)
    256 	}
    257 	if b.String() != "broot" {
    258 		t.Errorf("expected %q got %q", "broot", b.String())
    259 	}
    260 }
    261 
    262 // Issue 7032
    263 func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
    264 	master := "{{define \"master\"}}{{end}}"
    265 	tmpl := New("master")
    266 	tree, err := parse.Parse("master", master, "", "", nil)
    267 	if err != nil {
    268 		t.Fatalf("unexpected parse err: %v", err)
    269 	}
    270 	masterTree := tree["master"]
    271 	tmpl.AddParseTree("master", masterTree) // used to panic
    272 }
    273 
    274 func TestRedefinition(t *testing.T) {
    275 	var tmpl *Template
    276 	var err error
    277 	if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
    278 		t.Fatalf("parse 1: %v", err)
    279 	}
    280 	if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err == nil {
    281 		t.Fatal("expected error")
    282 	}
    283 	if !strings.Contains(err.Error(), "redefinition") {
    284 		t.Fatalf("expected redefinition error; got %v", err)
    285 	}
    286 	if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err == nil {
    287 		t.Fatal("expected error")
    288 	}
    289 	if !strings.Contains(err.Error(), "redefinition") {
    290 		t.Fatalf("expected redefinition error; got %v", err)
    291 	}
    292 }
    293 
    294 // Issue 10879
    295 func TestEmptyTemplateCloneCrash(t *testing.T) {
    296 	t1 := New("base")
    297 	t1.Clone() // used to panic
    298 }
    299 
    300 // Issue 10910, 10926
    301 func TestTemplateLookUp(t *testing.T) {
    302 	t1 := New("foo")
    303 	if t1.Lookup("foo") != nil {
    304 		t.Error("Lookup returned non-nil value for undefined template foo")
    305 	}
    306 	t1.New("bar")
    307 	if t1.Lookup("bar") != nil {
    308 		t.Error("Lookup returned non-nil value for undefined template bar")
    309 	}
    310 	t1.Parse(`{{define "foo"}}test{{end}}`)
    311 	if t1.Lookup("foo") == nil {
    312 		t.Error("Lookup returned nil value for defined template")
    313 	}
    314 }
    315 
    316 func TestNew(t *testing.T) {
    317 	// template with same name already exists
    318 	t1, _ := New("test").Parse(`{{define "test"}}foo{{end}}`)
    319 	t2 := t1.New("test")
    320 
    321 	if t1.common != t2.common {
    322 		t.Errorf("t1 & t2 didn't share common struct; got %v != %v", t1.common, t2.common)
    323 	}
    324 	if t1.Tree == nil {
    325 		t.Error("defined template got nil Tree")
    326 	}
    327 	if t2.Tree != nil {
    328 		t.Error("undefined template got non-nil Tree")
    329 	}
    330 
    331 	containsT1 := false
    332 	for _, tmpl := range t1.Templates() {
    333 		if tmpl == t2 {
    334 			t.Error("Templates included undefined template")
    335 		}
    336 		if tmpl == t1 {
    337 			containsT1 = true
    338 		}
    339 	}
    340 	if !containsT1 {
    341 		t.Error("Templates didn't include defined template")
    342 	}
    343 }
    344 
    345 func TestParse(t *testing.T) {
    346 	// In multiple calls to Parse with the same receiver template, only one call
    347 	// can contain text other than space, comments, and template definitions
    348 	var err error
    349 	t1 := New("test")
    350 	if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
    351 		t.Fatalf("parsing test: %s", err)
    352 	}
    353 	if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil {
    354 		t.Fatalf("parsing test: %s", err)
    355 	}
    356 	if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
    357 		t.Fatalf("parsing test: %s", err)
    358 	}
    359 	if _, err = t1.Parse(`{{define "test"}}foo{{end}}`); err == nil {
    360 		t.Fatal("no error from redefining a template")
    361 	}
    362 	if !strings.Contains(err.Error(), "redefinition") {
    363 		t.Fatalf("expected redefinition error; got %v", err)
    364 	}
    365 }
    366