Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / text / template / exec_test.go
index 6414953..683e9ac 100644 (file)
@@ -63,8 +63,11 @@ type T struct {
        BinaryFunc      func(string, string) string
        VariadicFunc    func(...string) string
        VariadicFuncInt func(int, ...string) string
+       NilOKFunc       func(*int) bool
        // Template to test evaluation of templates.
        Tmpl *Template
+       // Unexported field; cannot be accessed by template.
+       unexported int
 }
 
 type U struct {
@@ -125,6 +128,7 @@ var tVal = &T{
        BinaryFunc:        func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
        VariadicFunc:      func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
        VariadicFuncInt:   func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
+       NilOKFunc:         func(s *int) bool { return s == nil },
        Tmpl:              Must(New("x").Parse("test template")), // "x" is the value of .X
 }
 
@@ -220,6 +224,7 @@ var execTests = []execTest{
        // Trivial cases.
        {"empty", "", "", nil, true},
        {"text", "some text", "some text", nil, true},
+       {"nil action", "{{nil}}", "", nil, false},
 
        // Ideal constants.
        {"ideal int", "{{typeOf 3}}", "int", 0, true},
@@ -228,10 +233,12 @@ var execTests = []execTest{
        {"ideal complex", "{{typeOf 1i}}", "complex128", 0, true},
        {"ideal int", "{{typeOf " + bigInt + "}}", "int", 0, true},
        {"ideal too big", "{{typeOf " + bigUint + "}}", "", 0, false},
+       {"ideal nil without type", "{{nil}}", "", 0, false},
 
        // Fields of structs.
        {".X", "-{{.X}}-", "-x-", tVal, true},
        {".U.V", "-{{.U.V}}-", "-v-", tVal, true},
+       {".unexported", "{{.unexported}}", "", tVal, false},
 
        // Fields on maps.
        {"map .one", "{{.MSI.one}}", "1", tVal, true},
@@ -292,7 +299,8 @@ var execTests = []execTest{
        {".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
        {".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
        {".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
-       {".Method3(nil)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", tVal, true},
+       {".Method3(nil constant)", "-{{.Method3 nil}}-", "-Method3: <nil>-", tVal, true},
+       {".Method3(nil value)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", tVal, true},
        {"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
        {"method on chained var",
                "{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
@@ -303,6 +311,8 @@ var execTests = []execTest{
        {"chained method on variable",
                "{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
                "true", tVal, true},
+       {".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
+       {".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
 
        // Function call builtin.
        {".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
@@ -321,14 +331,25 @@ var execTests = []execTest{
        {".VariadicFuncBad0", "{{call .VariadicFunc 3}}", "", tVal, false},
        {".VariadicFuncIntBad0", "{{call .VariadicFuncInt}}", "", tVal, false},
        {".VariadicFuncIntBad`", "{{call .VariadicFuncInt `x`}}", "", tVal, false},
+       {".VariadicFuncNilBad", "{{call .VariadicFunc nil}}", "", tVal, false},
 
        // Pipelines.
        {"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
        {"pipeline func", "-{{call .VariadicFunc `llo` | call .VariadicFunc `he` }}-", "-<he+<llo>>-", tVal, true},
 
+       // Parenthesized expressions
+       {"parens in pipeline", "{{printf `%d %d %d` (1) (2 | add 3) (add 4 (add 5 6))}}", "1 5 15", tVal, true},
+
+       // Parenthesized expressions with field accesses
+       {"parens: $ in paren", "{{($).X}}", "x", tVal, true},
+       {"parens: $.GetU in paren", "{{($.GetU).V}}", "v", tVal, true},
+       {"parens: $ in paren in pipe", "{{($ | echo).X}}", "x", tVal, true},
+       {"parens: spaces and args", `{{(makemap "up" "down" "left" "right").left}}`, "right", tVal, true},
+
        // If.
        {"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
        {"if false", "{{if false}}TRUE{{else}}FALSE{{end}}", "FALSE", tVal, true},
+       {"if nil", "{{if nil}}TRUE{{end}}", "", tVal, false},
        {"if 1", "{{if 1}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
        {"if 0", "{{if 0}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
        {"if 1.5", "{{if 1.5}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
@@ -348,7 +369,8 @@ var execTests = []execTest{
 
        // Print etc.
        {"print", `{{print "hello, print"}}`, "hello, print", tVal, true},
-       {"print", `{{print 1 2 3}}`, "1 2 3", tVal, true},
+       {"print 123", `{{print 1 2 3}}`, "1 2 3", tVal, true},
+       {"print nil", `{{print nil}}`, "<nil>", tVal, true},
        {"println", `{{println 1 2 3}}`, "1 2 3\n", tVal, true},
        {"printf int", `{{printf "%04x" 127}}`, "007f", tVal, true},
        {"printf float", `{{printf "%g" 3.5}}`, "3.5", tVal, true},
@@ -388,6 +410,7 @@ var execTests = []execTest{
        {"map[one]", "{{index .MSI `one`}}", "1", tVal, true},
        {"map[two]", "{{index .MSI `two`}}", "2", tVal, true},
        {"map[NO]", "{{index .MSI `XXX`}}", "0", tVal, true},
+       {"map[nil]", "{{index .MSI nil}}", "0", tVal, true},
        {"map[WRONG]", "{{index .MSI 10}}", "", tVal, false},
        {"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true},
 
@@ -474,6 +497,8 @@ var execTests = []execTest{
        // Pipelined arg was not being type-checked.
        {"bug8a", "{{3|oneArg}}", "", tVal, false},
        {"bug8b", "{{4|dddArg 3}}", "", tVal, false},
+       // A bug was introduced that broke map lookups for lower-case names.
+       {"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true},
 }
 
 func zeroArgs() string {
@@ -508,6 +533,29 @@ func vfunc(V, *V) string {
        return "vfunc"
 }
 
+func add(args ...int) int {
+       sum := 0
+       for _, x := range args {
+               sum += x
+       }
+       return sum
+}
+
+func echo(arg interface{}) interface{} {
+       return arg
+}
+
+func makemap(arg ...string) map[string]string {
+       if len(arg)%2 != 0 {
+               panic("bad makemap")
+       }
+       m := make(map[string]string)
+       for i := 0; i < len(arg); i += 2 {
+               m[arg[i]] = arg[i+1]
+       }
+       return m
+}
+
 func stringer(s fmt.Stringer) string {
        return s.String()
 }
@@ -515,8 +563,11 @@ func stringer(s fmt.Stringer) string {
 func testExecute(execTests []execTest, template *Template, t *testing.T) {
        b := new(bytes.Buffer)
        funcs := FuncMap{
+               "add":      add,
                "count":    count,
                "dddArg":   dddArg,
+               "echo":     echo,
+               "makemap":  makemap,
                "oneArg":   oneArg,
                "typeOf":   typeOf,
                "vfunc":    vfunc,
@@ -624,6 +675,32 @@ func TestExecuteError(t *testing.T) {
        }
 }
 
+const execErrorText = `line 1
+line 2
+line 3
+{{template "one" .}}
+{{define "one"}}{{template "two" .}}{{end}}
+{{define "two"}}{{template "three" .}}{{end}}
+{{define "three"}}{{index "hi" $}}{{end}}`
+
+// Check that an error from a nested template contains all the relevant information.
+func TestExecError(t *testing.T) {
+       tmpl, err := New("top").Parse(execErrorText)
+       if err != nil {
+               t.Fatal("parse error:", err)
+       }
+       var b bytes.Buffer
+       err = tmpl.Execute(&b, 5) // 5 is out of range indexing "hi"
+       if err == nil {
+               t.Fatal("expected error")
+       }
+       const want = `template: top:7:20: executing "three" at <index "hi" $>: error calling index: index out of range: 5`
+       got := err.Error()
+       if got != want {
+               t.Errorf("expected\n%q\ngot\n%q", want, got)
+       }
+}
+
 func TestJSEscaping(t *testing.T) {
        testCases := []struct {
                in, exp string
@@ -734,3 +811,8 @@ func TestTree(t *testing.T) {
                t.Errorf("expected %q got %q", expect, result)
        }
 }
+
+func TestExecuteOnNewTemplate(t *testing.T) {
+       // This is issue 3872.
+       _ = New("Name").Templates()
+}