diff options
Diffstat (limited to 'libgo/go/text/template/exec_test.go')
-rw-r--r-- | libgo/go/text/template/exec_test.go | 86 |
1 files changed, 84 insertions, 2 deletions
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go index 64149533b3e..683e9ac76b6 100644 --- a/libgo/go/text/template/exec_test.go +++ b/libgo/go/text/template/exec_test.go @@ -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() +} |