github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/text/template/multi_test.go (about) 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 multiple-template parsing and execution. 8 9 import ( 10 "bytes" 11 "fmt" 12 "os" 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 func TestParseFS(t *testing.T) { 158 fs := os.DirFS("testdata") 159 160 { 161 _, err := ParseFS(fs, "DOES NOT EXIST") 162 if err == nil { 163 t.Error("expected error for non-existent file; got none") 164 } 165 } 166 167 { 168 template := New("root") 169 _, err := template.ParseFS(fs, "file1.tmpl", "file2.tmpl") 170 if err != nil { 171 t.Fatalf("error parsing files: %v", err) 172 } 173 testExecute(multiExecTests, template, t) 174 } 175 176 { 177 template := New("root") 178 _, err := template.ParseFS(fs, "file*.tmpl") 179 if err != nil { 180 t.Fatalf("error parsing files: %v", err) 181 } 182 testExecute(multiExecTests, template, t) 183 } 184 } 185 186 // In these tests, actual content (not just template definitions) comes from the parsed files. 187 188 var templateFileExecTests = []execTest{ 189 {"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true}, 190 } 191 192 func TestParseFilesWithData(t *testing.T) { 193 template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl") 194 if err != nil { 195 t.Fatalf("error parsing files: %v", err) 196 } 197 testExecute(templateFileExecTests, template, t) 198 } 199 200 func TestParseGlobWithData(t *testing.T) { 201 template, err := New("root").ParseGlob("testdata/tmpl*.tmpl") 202 if err != nil { 203 t.Fatalf("error parsing files: %v", err) 204 } 205 testExecute(templateFileExecTests, template, t) 206 } 207 208 const ( 209 cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}` 210 cloneText2 = `{{define "b"}}b{{end}}` 211 cloneText3 = `{{define "c"}}root{{end}}` 212 cloneText4 = `{{define "c"}}clone{{end}}` 213 ) 214 215 func TestClone(t *testing.T) { 216 // Create some templates and clone the root. 217 root, err := New("root").Parse(cloneText1) 218 if err != nil { 219 t.Fatal(err) 220 } 221 _, err = root.Parse(cloneText2) 222 if err != nil { 223 t.Fatal(err) 224 } 225 clone := Must(root.Clone()) 226 // Add variants to both. 227 _, err = root.Parse(cloneText3) 228 if err != nil { 229 t.Fatal(err) 230 } 231 _, err = clone.Parse(cloneText4) 232 if err != nil { 233 t.Fatal(err) 234 } 235 // Verify that the clone is self-consistent. 236 for k, v := range clone.tmpl { 237 if k == clone.name && v.tmpl[k] != clone { 238 t.Error("clone does not contain root") 239 } 240 if v != v.tmpl[v.name] { 241 t.Errorf("clone does not contain self for %q", k) 242 } 243 } 244 // Execute root. 245 var b bytes.Buffer 246 err = root.ExecuteTemplate(&b, "a", 0) 247 if err != nil { 248 t.Fatal(err) 249 } 250 if b.String() != "broot" { 251 t.Errorf("expected %q got %q", "broot", b.String()) 252 } 253 // Execute copy. 254 b.Reset() 255 err = clone.ExecuteTemplate(&b, "a", 0) 256 if err != nil { 257 t.Fatal(err) 258 } 259 if b.String() != "bclone" { 260 t.Errorf("expected %q got %q", "bclone", b.String()) 261 } 262 } 263 264 func TestAddParseTree(t *testing.T) { 265 // Create some templates. 266 root, err := New("root").Parse(cloneText1) 267 if err != nil { 268 t.Fatal(err) 269 } 270 _, err = root.Parse(cloneText2) 271 if err != nil { 272 t.Fatal(err) 273 } 274 // Add a new parse tree. 275 tree, err := parse.Parse("cloneText3", cloneText3, "", "", nil, builtins()) 276 if err != nil { 277 t.Fatal(err) 278 } 279 added, err := root.AddParseTree("c", tree["c"]) 280 if err != nil { 281 t.Fatal(err) 282 } 283 // Execute. 284 var b bytes.Buffer 285 err = added.ExecuteTemplate(&b, "a", 0) 286 if err != nil { 287 t.Fatal(err) 288 } 289 if b.String() != "broot" { 290 t.Errorf("expected %q got %q", "broot", b.String()) 291 } 292 } 293 294 // Issue 7032 295 func TestAddParseTreeToUnparsedTemplate(t *testing.T) { 296 master := "{{define \"master\"}}{{end}}" 297 tmpl := New("master") 298 tree, err := parse.Parse("master", master, "", "", nil) 299 if err != nil { 300 t.Fatalf("unexpected parse err: %v", err) 301 } 302 masterTree := tree["master"] 303 tmpl.AddParseTree("master", masterTree) // used to panic 304 } 305 306 func TestRedefinition(t *testing.T) { 307 var tmpl *Template 308 var err error 309 if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil { 310 t.Fatalf("parse 1: %v", err) 311 } 312 if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err != nil { 313 t.Fatalf("got error %v, expected nil", err) 314 } 315 if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err != nil { 316 t.Fatalf("got error %v, expected nil", err) 317 } 318 } 319 320 // Issue 10879 321 func TestEmptyTemplateCloneCrash(t *testing.T) { 322 t1 := New("base") 323 t1.Clone() // used to panic 324 } 325 326 // Issue 10910, 10926 327 func TestTemplateLookUp(t *testing.T) { 328 t1 := New("foo") 329 if t1.Lookup("foo") != nil { 330 t.Error("Lookup returned non-nil value for undefined template foo") 331 } 332 t1.New("bar") 333 if t1.Lookup("bar") != nil { 334 t.Error("Lookup returned non-nil value for undefined template bar") 335 } 336 t1.Parse(`{{define "foo"}}test{{end}}`) 337 if t1.Lookup("foo") == nil { 338 t.Error("Lookup returned nil value for defined template") 339 } 340 } 341 342 func TestNew(t *testing.T) { 343 // template with same name already exists 344 t1, _ := New("test").Parse(`{{define "test"}}foo{{end}}`) 345 t2 := t1.New("test") 346 347 if t1.common != t2.common { 348 t.Errorf("t1 & t2 didn't share common struct; got %v != %v", t1.common, t2.common) 349 } 350 if t1.Tree == nil { 351 t.Error("defined template got nil Tree") 352 } 353 if t2.Tree != nil { 354 t.Error("undefined template got non-nil Tree") 355 } 356 357 containsT1 := false 358 for _, tmpl := range t1.Templates() { 359 if tmpl == t2 { 360 t.Error("Templates included undefined template") 361 } 362 if tmpl == t1 { 363 containsT1 = true 364 } 365 } 366 if !containsT1 { 367 t.Error("Templates didn't include defined template") 368 } 369 } 370 371 func TestParse(t *testing.T) { 372 // In multiple calls to Parse with the same receiver template, only one call 373 // can contain text other than space, comments, and template definitions 374 t1 := New("test") 375 if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil { 376 t.Fatalf("parsing test: %s", err) 377 } 378 if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil { 379 t.Fatalf("parsing test: %s", err) 380 } 381 if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil { 382 t.Fatalf("parsing test: %s", err) 383 } 384 } 385 386 func TestEmptyTemplate(t *testing.T) { 387 cases := []struct { 388 defn []string 389 in string 390 want string 391 }{ 392 {[]string{"x", "y"}, "", "y"}, 393 {[]string{""}, "once", ""}, 394 {[]string{"", ""}, "twice", ""}, 395 {[]string{"{{.}}", "{{.}}"}, "twice", "twice"}, 396 {[]string{"{{/* a comment */}}", "{{/* a comment */}}"}, "comment", ""}, 397 {[]string{"{{.}}", ""}, "twice", ""}, 398 } 399 400 for i, c := range cases { 401 root := New("root") 402 403 var ( 404 m *Template 405 err error 406 ) 407 for _, d := range c.defn { 408 m, err = root.New(c.in).Parse(d) 409 if err != nil { 410 t.Fatal(err) 411 } 412 } 413 buf := &bytes.Buffer{} 414 if err := m.Execute(buf, c.in); err != nil { 415 t.Error(i, err) 416 continue 417 } 418 if buf.String() != c.want { 419 t.Errorf("expected string %q: got %q", c.want, buf.String()) 420 } 421 } 422 } 423 424 // Issue 19249 was a regression in 1.8 caused by the handling of empty 425 // templates added in that release, which got different answers depending 426 // on the order templates appeared in the internal map. 427 func TestIssue19294(t *testing.T) { 428 // The empty block in "xhtml" should be replaced during execution 429 // by the contents of "stylesheet", but if the internal map associating 430 // names with templates is built in the wrong order, the empty block 431 // looks non-empty and this doesn't happen. 432 var inlined = map[string]string{ 433 "stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`, 434 "xhtml": `{{block "stylesheet" .}}{{end}}`, 435 } 436 all := []string{"stylesheet", "xhtml"} 437 for i := 0; i < 100; i++ { 438 res, err := New("title.xhtml").Parse(`{{template "xhtml" .}}`) 439 if err != nil { 440 t.Fatal(err) 441 } 442 for _, name := range all { 443 _, err := res.New(name).Parse(inlined[name]) 444 if err != nil { 445 t.Fatal(err) 446 } 447 } 448 var buf bytes.Buffer 449 res.Execute(&buf, 0) 450 if buf.String() != "stylesheet" { 451 t.Fatalf("iteration %d: got %q; expected %q", i, buf.String(), "stylesheet") 452 } 453 } 454 }