diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-16 15:47:21 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-09-16 15:47:21 +0000 |
commit | adb0401dac41c81571722312d4586b2693f95aa6 (patch) | |
tree | ea2b52e3c258d6b6d9356977c683c7f72a4a5fd5 /libgo/go/old/template/template_test.go | |
parent | 5548ca3540bccbc908a45942896d635ea5f1c23f (diff) | |
download | gcc-adb0401dac41c81571722312d4586b2693f95aa6.zip gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.gz gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.bz2 |
Update Go library to r60.
From-SVN: r178910
Diffstat (limited to 'libgo/go/old/template/template_test.go')
-rw-r--r-- | libgo/go/old/template/template_test.go | 804 |
1 files changed, 804 insertions, 0 deletions
diff --git a/libgo/go/old/template/template_test.go b/libgo/go/old/template/template_test.go new file mode 100644 index 0000000..eae8011 --- /dev/null +++ b/libgo/go/old/template/template_test.go @@ -0,0 +1,804 @@ +// 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" + "io/ioutil" + "json" + "os" + "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 + HeaderPtr *string + Integer int + IntegerPtr *int + NilPtr *int + 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 + JSON interface{} + Innermap U + Stringmap map[string]string + Ptrmap map[string]*string + Iface interface{} + Ifaceptr interface{} +} + +func (s *S) PointerMethod() string { return "ptrmethod!" } + +func (s S) ValueMethod() string { return "valmethod!" } + +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, string, ...interface{}) { + return func(w io.Writer, format string, v ...interface{}) { + if len(v) != 1 { + panic("test writer expected one arg") + } + io.WriteString(w, f(v[0])) + } +} + +func multiword(w io.Writer, format string, value ...interface{}) { + for _, v := range value { + fmt.Fprintf(w, "<%v>", v) + } +} + +func printf(w io.Writer, format string, v ...interface{}) { + io.WriteString(w, fmt.Sprintf(v[0].(string), v[1:]...)) +} + +var formatters = FormatterMap{ + "uppercase": writer(uppercase), + "+1": writer(plus1), + "multiword": multiword, + "printf": printf, +} + +var tests = []*Test{ + // Simple + &Test{"", "", ""}, + &Test{"abc", "abc", ""}, + &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", "", ""}, + &Test{"\tSome Text\t\n", "\tSome Text\t\n", ""}, + &Test{" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""}, + + // Variables at top level + &Test{ + in: "{Header}={Integer}\n", + + out: "Header=77\n", + }, + + &Test{ + in: "Pointers: {*HeaderPtr}={*IntegerPtr}\n", + + out: "Pointers: Header=77\n", + }, + + &Test{ + in: "Stars but not pointers: {*Header}={*Integer}\n", + + out: "Stars but not pointers: Header=77\n", + }, + + &Test{ + in: "nil pointer: {*NilPtr}={*Integer}\n", + + out: "nil pointer: <nil>=77\n", + }, + + &Test{ + in: `{"Strings" ":"} {""} {"|"} {"\t\u0123 \x23\\"} {"\"}{\\"}`, + + out: "Strings: | \t\u0123 \x23\\ \"}{\\", + }, + + &Test{ + in: "{`Raw strings` `:`} {``} {`|`} {`\\t\\u0123 \\x23\\`} {`}{\\`}", + + out: "Raw strings: | \\t\\u0123 \\x23\\ }{\\", + }, + + &Test{ + in: "Characters: {'a'} {'\\u0123'} {' '} {'{'} {'|'} {'}'}", + + out: "Characters: 97 291 32 123 124 125", + }, + + &Test{ + in: "Integers: {1} {-2} {+42} {0777} {0x0a}", + + out: "Integers: 1 -2 42 511 10", + }, + + &Test{ + in: "Floats: {.5} {-.5} {1.1} {-2.2} {+42.1} {1e10} {1.2e-3} {1.2e3} {-1.2e3}", + + out: "Floats: 0.5 -0.5 1.1 -2.2 42.1 1e+10 0.0012 1200 -1200", + }, + + // Method at top level + &Test{ + in: "ptrmethod={PointerMethod}\n", + + out: "ptrmethod=ptrmethod!\n", + }, + + &Test{ + in: "valmethod={ValueMethod}\n", + + out: "valmethod=valmethod!\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", + }, + + &Test{ + in: "{.section Integer}{@}{.end}", + + out: "77", + }, + + // 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: "{.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", + }, + // Same but with a space before {.end}: was a bug. + &Test{ + in: "{.repeated section Vec }\n" + + "{@} {.end}\n", + + out: "elt1 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", + }, + + &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", + }, + + // Maps + + &Test{ + in: "{Mp.mapkey}\n", + + out: "Ahoy!\n", + }, + &Test{ + in: "{Innermap.Mp.innerkey}\n", + + out: "55\n", + }, + &Test{ + in: "{.section Innermap}{.section Mp}{innerkey}{.end}{.end}\n", + + out: "55\n", + }, + &Test{ + in: "{.section JSON}{.repeated section maps}{a}{b}{.end}{.end}\n", + + out: "1234\n", + }, + &Test{ + in: "{Stringmap.stringkey1}\n", + + out: "stringresult\n", + }, + &Test{ + in: "{.repeated section Stringmap}\n" + + "{@}\n" + + "{.end}", + + out: "stringresult\n" + + "stringresult\n", + }, + &Test{ + in: "{.repeated section Stringmap}\n" + + "\t{@}\n" + + "{.end}", + + out: "\tstringresult\n" + + "\tstringresult\n", + }, + &Test{ + in: "{*Ptrmap.stringkey1}\n", + + out: "pointedToString\n", + }, + &Test{ + in: "{.repeated section Ptrmap}\n" + + "{*@}\n" + + "{.end}", + + out: "pointedToString\n" + + "pointedToString\n", + }, + + // Interface values + + &Test{ + in: "{Iface}", + + out: "[1 2 3]", + }, + &Test{ + in: "{.repeated section Iface}{@}{.alternates with} {.end}", + + out: "1 2 3", + }, + &Test{ + in: "{.section Iface}{@}{.end}", + + out: "[1 2 3]", + }, + &Test{ + in: "{.section Ifaceptr}{Item} {Value}{.end}", + + out: "Item Value", + }, +} + +func TestAll(t *testing.T) { + // Parse + testAll(t, func(test *Test) (*Template, os.Error) { return Parse(test.in, formatters) }) + // ParseFile + testAll(t, func(test *Test) (*Template, os.Error) { + err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600) + if err != nil { + t.Error("unexpected write error:", err) + return nil, err + } + return ParseFile("_test/test.tmpl", formatters) + }) + // tmpl.ParseFile + testAll(t, func(test *Test) (*Template, os.Error) { + err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600) + if err != nil { + t.Error("unexpected write error:", err) + return nil, err + } + tmpl := New(formatters) + return tmpl, tmpl.ParseFile("_test/test.tmpl") + }) +} + +func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) { + s := new(S) + // initialized by hand for clarity. + s.Header = "Header" + s.HeaderPtr = &s.Header + s.Integer = 77 + s.IntegerPtr = &s.Integer + 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!" + json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.JSON) + s.Innermap.Mp = make(map[string]int) + s.Innermap.Mp["innerkey"] = 55 + s.Stringmap = make(map[string]string) + s.Stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent + s.Stringmap["stringkey2"] = "stringresult" + s.Ptrmap = make(map[string]*string) + x := "pointedToString" + s.Ptrmap["stringkey1"] = &x // the same value so repeated section is order-independent + s.Ptrmap["stringkey2"] = &x + s.Iface = []int{1, 2, 3} + s.Ifaceptr = &T{"Item", "Value"} + + var buf bytes.Buffer + for _, test := range tests { + buf.Reset() + tmpl, err := parseFunc(test) + if err != nil { + t.Error("unexpected parse error: ", err) + continue + } + err = tmpl.Execute(&buf, s) + if test.err == "" { + if err != nil { + t.Error("unexpected execute error:", err) + } + } else { + if err == nil { + t.Errorf("expected execute error %q, got nil", test.err) + } else if 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(&b, mp) + if err != nil { + t.Error("unexpected execute error:", err) + } + s := b.String() + expect := "template: Ahoy!" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, s) + } +} + +func TestMapNoEntry(t *testing.T) { + mp := make(map[string]int) + tmpl, err := Parse("template: {notthere}!", nil) + if err != nil { + t.Error("unexpected parse error:", err) + } + var b bytes.Buffer + err = tmpl.Execute(&b, mp) + if err != nil { + t.Error("unexpected execute error:", err) + } + s := b.String() + expect := "template: 0!" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, 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(&b, "hello") + if err != nil { + t.Error("unexpected execute error:", err) + } + s := b.String() + expect := "template: hello" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, 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(&b, "hello") + if err != nil { + t.Error("unexpected parse error:", err) + } + s := b.String() + expect := "template: hello" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, s) + } + err = tmpl.Execute(&b, "hello") + if err != nil { + t.Error("unexpected parse error:", err) + } + s = b.String() + expect += expect + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, 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(&b, "hello") + 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(&buf, s) + 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()) + } +} + +func TestHTMLFormatterWithByte(t *testing.T) { + s := "Test string." + b := []byte(s) + var buf bytes.Buffer + HTMLFormatter(&buf, "", b) + bs := buf.String() + if bs != s { + t.Errorf("munged []byte, expected: %s got: %s", s, bs) + } +} + +type UF struct { + I int + s string +} + +func TestReferenceToUnexported(t *testing.T) { + u := &UF{3, "hello"} + var buf bytes.Buffer + input := "{.section @}{I}{s}{.end}" + tmpl, err := Parse(input, nil) + if err != nil { + t.Fatal("unexpected parse error:", err) + } + err = tmpl.Execute(&buf, u) + if err == nil { + t.Fatal("expected execute error, got none") + } + if strings.Index(err.String(), "not exported") < 0 { + t.Fatal("expected unexported error; got", err) + } +} + +var formatterTests = []Test{ + { + in: "{Header|uppercase}={Integer|+1}\n" + + "{Header|html}={Integer|str}\n", + + out: "HEADER=78\n" + + "Header=77\n", + }, + + { + in: "{Header|uppercase}={Integer Header|multiword}\n" + + "{Header|html}={Header Integer|multiword}\n" + + "{Header|html}={Header Integer}\n", + + out: "HEADER=<77><Header>\n" + + "Header=<Header><77>\n" + + "Header=Header77\n", + }, + { + in: "{Raw}\n" + + "{Raw|html}\n", + + out: "a <&> b\n" + + "a <&> b\n", + }, + { + in: "{Bytes}", + out: "hello", + }, + { + in: "{Raw|uppercase|html|html}", + out: "A &lt;&amp;&gt; B", + }, + { + in: "{Header Integer|multiword|html}", + out: "<Header><77>", + }, + { + in: "{Integer|no_formatter|html}", + err: `unknown formatter: "no_formatter"`, + }, + { + in: "{Integer|||||}", // empty string is a valid formatter + out: "77", + }, + { + in: `{"%.02f 0x%02X" 1.1 10|printf}`, + out: "1.10 0x0A", + }, + { + in: `{""|}{""||}{""|printf}`, // Issue #1896. + out: "", + }, +} + +func TestFormatters(t *testing.T) { + data := map[string]interface{}{ + "Header": "Header", + "Integer": 77, + "Raw": "a <&> b", + "Bytes": []byte("hello"), + } + for _, c := range formatterTests { + tmpl, err := Parse(c.in, formatters) + if err != nil { + if c.err == "" { + t.Error("unexpected parse error:", err) + continue + } + if strings.Index(err.String(), c.err) < 0 { + t.Errorf("unexpected error: expected %q, got %q", c.err, err.String()) + continue + } + } else { + if c.err != "" { + t.Errorf("For %q, expected error, got none.", c.in) + continue + } + buf := bytes.NewBuffer(nil) + err = tmpl.Execute(buf, data) + if err != nil { + t.Error("unexpected Execute error: ", err) + continue + } + actual := buf.String() + if actual != c.out { + t.Errorf("for %q: expected %q but got %q.", c.in, c.out, actual) + } + } + } +} |