hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

multi_test.go (12123B)

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