github.com/filosottile/go@v0.0.0-20170906193555-dbed9972d994/src/html/template/template_test.go (about)

     1  // Copyright 2016 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_test
     6  
     7  import (
     8  	"bytes"
     9  	. "html/template"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  func TestTemplateClone(t *testing.T) {
    15  	// https://golang.org/issue/12996
    16  	orig := New("name")
    17  	clone, err := orig.Clone()
    18  	if err != nil {
    19  		t.Fatal(err)
    20  	}
    21  	if len(clone.Templates()) != len(orig.Templates()) {
    22  		t.Fatalf("Invalid length of t.Clone().Templates()")
    23  	}
    24  
    25  	const want = "stuff"
    26  	parsed := Must(clone.Parse(want))
    27  	var buf bytes.Buffer
    28  	err = parsed.Execute(&buf, nil)
    29  	if err != nil {
    30  		t.Fatal(err)
    31  	}
    32  	if got := buf.String(); got != want {
    33  		t.Fatalf("got %q; want %q", got, want)
    34  	}
    35  }
    36  
    37  func TestRedefineNonEmptyAfterExecution(t *testing.T) {
    38  	c := newTestCase(t)
    39  	c.mustParse(c.root, `foo`)
    40  	c.mustExecute(c.root, nil, "foo")
    41  	c.mustNotParse(c.root, `bar`)
    42  }
    43  
    44  func TestRedefineEmptyAfterExecution(t *testing.T) {
    45  	c := newTestCase(t)
    46  	c.mustParse(c.root, ``)
    47  	c.mustExecute(c.root, nil, "")
    48  	c.mustNotParse(c.root, `foo`)
    49  	c.mustExecute(c.root, nil, "")
    50  }
    51  
    52  func TestRedefineAfterNonExecution(t *testing.T) {
    53  	c := newTestCase(t)
    54  	c.mustParse(c.root, `{{if .}}<{{template "X"}}>{{end}}{{define "X"}}foo{{end}}`)
    55  	c.mustExecute(c.root, 0, "")
    56  	c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
    57  	c.mustExecute(c.root, 1, "&lt;foo>")
    58  }
    59  
    60  func TestRedefineAfterNamedExecution(t *testing.T) {
    61  	c := newTestCase(t)
    62  	c.mustParse(c.root, `<{{template "X" .}}>{{define "X"}}foo{{end}}`)
    63  	c.mustExecute(c.root, nil, "&lt;foo>")
    64  	c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
    65  	c.mustExecute(c.root, nil, "&lt;foo>")
    66  }
    67  
    68  func TestRedefineNestedByNameAfterExecution(t *testing.T) {
    69  	c := newTestCase(t)
    70  	c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
    71  	c.mustExecute(c.lookup("X"), nil, "foo")
    72  	c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
    73  	c.mustExecute(c.lookup("X"), nil, "foo")
    74  }
    75  
    76  func TestRedefineNestedByTemplateAfterExecution(t *testing.T) {
    77  	c := newTestCase(t)
    78  	c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
    79  	c.mustExecute(c.lookup("X"), nil, "foo")
    80  	c.mustNotParse(c.lookup("X"), `bar`)
    81  	c.mustExecute(c.lookup("X"), nil, "foo")
    82  }
    83  
    84  func TestRedefineSafety(t *testing.T) {
    85  	c := newTestCase(t)
    86  	c.mustParse(c.root, `<html><a href="{{template "X"}}">{{define "X"}}{{end}}`)
    87  	c.mustExecute(c.root, nil, `<html><a href="">`)
    88  	// Note: Every version of Go prior to Go 1.8 accepted the redefinition of "X"
    89  	// on the next line, but luckily kept it from being used in the outer template.
    90  	// Now we reject it, which makes clearer that we're not going to use it.
    91  	c.mustNotParse(c.root, `{{define "X"}}" bar="baz{{end}}`)
    92  	c.mustExecute(c.root, nil, `<html><a href="">`)
    93  }
    94  
    95  func TestRedefineTopUse(t *testing.T) {
    96  	c := newTestCase(t)
    97  	c.mustParse(c.root, `{{template "X"}}{{.}}{{define "X"}}{{end}}`)
    98  	c.mustExecute(c.root, 42, `42`)
    99  	c.mustNotParse(c.root, `{{define "X"}}<script>{{end}}`)
   100  	c.mustExecute(c.root, 42, `42`)
   101  }
   102  
   103  func TestRedefineOtherParsers(t *testing.T) {
   104  	c := newTestCase(t)
   105  	c.mustParse(c.root, ``)
   106  	c.mustExecute(c.root, nil, ``)
   107  	if _, err := c.root.ParseFiles("no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
   108  		t.Errorf("ParseFiles: %v\nwanted error about already having Executed", err)
   109  	}
   110  	if _, err := c.root.ParseGlob("*.no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
   111  		t.Errorf("ParseGlob: %v\nwanted error about already having Executed", err)
   112  	}
   113  	if _, err := c.root.AddParseTree("t1", c.root.Tree); err == nil || !strings.Contains(err.Error(), "Execute") {
   114  		t.Errorf("AddParseTree: %v\nwanted error about already having Executed", err)
   115  	}
   116  }
   117  
   118  type testCase struct {
   119  	t    *testing.T
   120  	root *Template
   121  }
   122  
   123  func newTestCase(t *testing.T) *testCase {
   124  	return &testCase{
   125  		t:    t,
   126  		root: New("root"),
   127  	}
   128  }
   129  
   130  func (c *testCase) lookup(name string) *Template {
   131  	return c.root.Lookup(name)
   132  }
   133  
   134  func (c *testCase) mustParse(t *Template, text string) {
   135  	_, err := t.Parse(text)
   136  	if err != nil {
   137  		c.t.Fatalf("parse: %v", err)
   138  	}
   139  }
   140  
   141  func (c *testCase) mustNotParse(t *Template, text string) {
   142  	_, err := t.Parse(text)
   143  	if err == nil {
   144  		c.t.Fatalf("parse: unexpected success")
   145  	}
   146  }
   147  
   148  func (c *testCase) mustExecute(t *Template, val interface{}, want string) {
   149  	var buf bytes.Buffer
   150  	err := t.Execute(&buf, val)
   151  	if err != nil {
   152  		c.t.Fatalf("execute: %v", err)
   153  	}
   154  	if buf.String() != want {
   155  		c.t.Fatalf("template output:\n%s\nwant:\n%s", buf.String(), want)
   156  	}
   157  }