1
0
mirror of https://github.com/golang/go synced 2024-10-05 06:21:24 -06:00
go/src/pkg/template/template_test.go
Robert Griesemer 45ca9f7a9e 1) Change default gofmt default settings for
parsing and printing to new syntax.

   Use -oldparser to parse the old syntax,
   use -oldprinter to print the old syntax.

2) Change default gofmt formatting settings
   to use tabs for indentation only and to use
   spaces for alignment. This will make the code
   alignment insensitive to an editor's tabwidth.

   Use -spaces=false to use tabs for alignment.

3) Manually changed src/exp/parser/parser_test.go
   so that it doesn't try to parse the parser's
   source files using the old syntax (they have
   new syntax now).

4) gofmt -w src misc test/bench

5th and last set of files.

R=rsc
CC=golang-dev
https://golang.org/cl/180050
2009-12-15 15:41:46 -08:00

469 lines
9.2 KiB
Go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package template
import (
"bytes"
"container/vector"
"fmt"
"io"
"strings"
"testing"
)
type Test struct {
in, out, err string
}
type T struct {
item string
value string
}
type U struct {
mp map[string]int
}
type S struct {
header string
integer int
raw string
innerT T
innerPointerT *T
data []T
pdata []*T
empty []*T
emptystring string
null []*T
vec *vector.Vector
true bool
false bool
mp map[string]string
innermap U
bytes []byte
}
var t1 = T{"ItemNumber1", "ValueNumber1"}
var t2 = T{"ItemNumber2", "ValueNumber2"}
func uppercase(v interface{}) string {
s := v.(string)
t := ""
for i := 0; i < len(s); i++ {
c := s[i]
if 'a' <= c && c <= 'z' {
c = c + 'A' - 'a'
}
t += string(c)
}
return t
}
func plus1(v interface{}) string {
i := v.(int)
return fmt.Sprint(i + 1)
}
func writer(f func(interface{}) string) (func(io.Writer, interface{}, string)) {
return func(w io.Writer, v interface{}, format string) {
io.WriteString(w, f(v))
}
}
var formatters = FormatterMap{
"uppercase": writer(uppercase),
"+1": writer(plus1),
}
var tests = []*Test{
// Simple
&Test{"", "", ""},
&Test{"abc\ndef\n", "abc\ndef\n", ""},
&Test{" {.meta-left} \n", "{", ""},
&Test{" {.meta-right} \n", "}", ""},
&Test{" {.space} \n", " ", ""},
&Test{" {.tab} \n", "\t", ""},
&Test{" {#comment} \n", "", ""},
// Variables at top level
&Test{
in: "{header}={integer}\n",
out: "Header=77\n",
},
// Section
&Test{
in: "{.section data }\n" +
"some text for the section\n" +
"{.end}\n",
out: "some text for the section\n",
},
&Test{
in: "{.section data }\n" +
"{header}={integer}\n" +
"{.end}\n",
out: "Header=77\n",
},
&Test{
in: "{.section pdata }\n" +
"{header}={integer}\n" +
"{.end}\n",
out: "Header=77\n",
},
&Test{
in: "{.section pdata }\n" +
"data present\n" +
"{.or}\n" +
"data not present\n" +
"{.end}\n",
out: "data present\n",
},
&Test{
in: "{.section empty }\n" +
"data present\n" +
"{.or}\n" +
"data not present\n" +
"{.end}\n",
out: "data not present\n",
},
&Test{
in: "{.section null }\n" +
"data present\n" +
"{.or}\n" +
"data not present\n" +
"{.end}\n",
out: "data not present\n",
},
&Test{
in: "{.section pdata }\n" +
"{header}={integer}\n" +
"{.section @ }\n" +
"{header}={integer}\n" +
"{.end}\n" +
"{.end}\n",
out: "Header=77\n" +
"Header=77\n",
},
&Test{
in: "{.section data}{.end} {header}\n",
out: " Header\n",
},
// Repeated
&Test{
in: "{.section pdata }\n" +
"{.repeated section @ }\n" +
"{item}={value}\n" +
"{.end}\n" +
"{.end}\n",
out: "ItemNumber1=ValueNumber1\n" +
"ItemNumber2=ValueNumber2\n",
},
&Test{
in: "{.section pdata }\n" +
"{.repeated section @ }\n" +
"{item}={value}\n" +
"{.or}\n" +
"this should not appear\n" +
"{.end}\n" +
"{.end}\n",
out: "ItemNumber1=ValueNumber1\n" +
"ItemNumber2=ValueNumber2\n",
},
&Test{
in: "{.section @ }\n" +
"{.repeated section empty }\n" +
"{item}={value}\n" +
"{.or}\n" +
"this should appear: empty field\n" +
"{.end}\n" +
"{.end}\n",
out: "this should appear: empty field\n",
},
&Test{
in: "{.repeated section pdata }\n" +
"{item}\n" +
"{.alternates with}\n" +
"is\nover\nmultiple\nlines\n" +
"{.end}\n",
out: "ItemNumber1\n" +
"is\nover\nmultiple\nlines\n" +
"ItemNumber2\n",
},
&Test{
in: "{.section pdata }\n" +
"{.repeated section @ }\n" +
"{item}={value}\n" +
"{.alternates with}DIVIDER\n" +
"{.or}\n" +
"this should not appear\n" +
"{.end}\n" +
"{.end}\n",
out: "ItemNumber1=ValueNumber1\n" +
"DIVIDER\n" +
"ItemNumber2=ValueNumber2\n",
},
&Test{
in: "{.repeated section vec }\n" +
"{@}\n" +
"{.end}\n",
out: "elt1\n" +
"elt2\n",
},
&Test{
in: "{.repeated section integer}{.end}",
err: "line 1: .repeated: cannot repeat integer (type int)",
},
// Nested names
&Test{
in: "{.section @ }\n" +
"{innerT.item}={innerT.value}\n" +
"{.end}",
out: "ItemNumber1=ValueNumber1\n",
},
&Test{
in: "{.section @ }\n" +
"{innerT.item}={.section innerT}{.section value}{@}{.end}{.end}\n" +
"{.end}",
out: "ItemNumber1=ValueNumber1\n",
},
// Formatters
&Test{
in: "{.section pdata }\n" +
"{header|uppercase}={integer|+1}\n" +
"{header|html}={integer|str}\n" +
"{.end}\n",
out: "HEADER=78\n" +
"Header=77\n",
},
&Test{
in: "{raw}\n" +
"{raw|html}\n",
out: "&<>!@ #$%^\n" +
"&amp;&lt;&gt;!@ #$%^\n",
},
&Test{
in: "{.section emptystring}emptystring{.end}\n" +
"{.section header}header{.end}\n",
out: "\nheader\n",
},
&Test{
in: "{.section true}1{.or}2{.end}\n" +
"{.section false}3{.or}4{.end}\n",
out: "1\n4\n",
},
&Test{
in: "{bytes}",
out: "hello",
},
// Maps
&Test{
in: "{mp.mapkey}\n",
out: "Ahoy!\n",
},
&Test{
in: "{innermap.mp.innerkey}\n",
out: "55\n",
},
}
func TestAll(t *testing.T) {
s := new(S)
// initialized by hand for clarity.
s.header = "Header"
s.integer = 77
s.raw = "&<>!@ #$%^"
s.innerT = t1
s.data = []T{t1, t2}
s.pdata = []*T{&t1, &t2}
s.empty = []*T{}
s.null = nil
s.vec = new(vector.Vector)
s.vec.Push("elt1")
s.vec.Push("elt2")
s.true = true
s.false = false
s.mp = make(map[string]string)
s.mp["mapkey"] = "Ahoy!"
s.innermap.mp = make(map[string]int)
s.innermap.mp["innerkey"] = 55
s.bytes = strings.Bytes("hello")
var buf bytes.Buffer
for _, test := range tests {
buf.Reset()
tmpl, err := Parse(test.in, formatters)
if err != nil {
t.Error("unexpected parse error:", err)
continue
}
err = tmpl.Execute(s, &buf)
if test.err == "" {
if err != nil {
t.Error("unexpected execute error:", err)
}
} else {
if err == nil || err.String() != test.err {
t.Errorf("expected execute error %q, got %q", test.err, err.String())
}
}
if buf.String() != test.out {
t.Errorf("for %q: expected %q got %q", test.in, test.out, buf.String())
}
}
}
func TestMapDriverType(t *testing.T) {
mp := map[string]string{"footer": "Ahoy!"}
tmpl, err := Parse("template: {footer}", nil)
if err != nil {
t.Error("unexpected parse error:", err)
}
var b bytes.Buffer
err = tmpl.Execute(mp, &b)
if err != nil {
t.Error("unexpected execute error:", err)
}
s := b.String()
expected := "template: Ahoy!"
if s != expected {
t.Errorf("failed passing string as data: expected %q got %q", "template: Ahoy!", s)
}
}
func TestStringDriverType(t *testing.T) {
tmpl, err := Parse("template: {@}", nil)
if err != nil {
t.Error("unexpected parse error:", err)
}
var b bytes.Buffer
err = tmpl.Execute("hello", &b)
if err != nil {
t.Error("unexpected execute error:", err)
}
s := b.String()
if s != "template: hello" {
t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s)
}
}
func TestTwice(t *testing.T) {
tmpl, err := Parse("template: {@}", nil)
if err != nil {
t.Error("unexpected parse error:", err)
}
var b bytes.Buffer
err = tmpl.Execute("hello", &b)
if err != nil {
t.Error("unexpected parse error:", err)
}
s := b.String()
text := "template: hello"
if s != text {
t.Errorf("failed passing string as data: expected %q got %q", text, s)
}
err = tmpl.Execute("hello", &b)
if err != nil {
t.Error("unexpected parse error:", err)
}
s = b.String()
text += text
if s != text {
t.Errorf("failed passing string as data: expected %q got %q", text, s)
}
}
func TestCustomDelims(t *testing.T) {
// try various lengths. zero should catch error.
for i := 0; i < 7; i++ {
for j := 0; j < 7; j++ {
tmpl := New(nil)
// first two chars deliberately the same to test equal left and right delims
ldelim := "$!#$%^&"[0:i]
rdelim := "$*&^%$!"[0:j]
tmpl.SetDelims(ldelim, rdelim)
// if braces, this would be template: {@}{.meta-left}{.meta-right}
text := "template: " +
ldelim + "@" + rdelim +
ldelim + ".meta-left" + rdelim +
ldelim + ".meta-right" + rdelim
err := tmpl.Parse(text)
if err != nil {
if i == 0 || j == 0 { // expected
continue
}
t.Error("unexpected parse error:", err)
} else if i == 0 || j == 0 {
t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
continue
}
var b bytes.Buffer
err = tmpl.Execute("hello", &b)
s := b.String()
if s != "template: hello"+ldelim+rdelim {
t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
}
}
}
}
// Test that a variable evaluates to the field itself and does not further indirection
func TestVarIndirection(t *testing.T) {
s := new(S)
// initialized by hand for clarity.
s.innerPointerT = &t1
var buf bytes.Buffer
input := "{.section @}{innerPointerT}{.end}"
tmpl, err := Parse(input, nil)
if err != nil {
t.Fatal("unexpected parse error:", err)
}
err = tmpl.Execute(s, &buf)
if err != nil {
t.Fatal("unexpected execute error:", err)
}
expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
if buf.String() != expect {
t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
}
}