2009-04-08 23:08:55 -06:00
|
|
|
// 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 (
|
2009-12-15 16:41:46 -07:00
|
|
|
"bytes"
|
|
|
|
"container/vector"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2010-03-10 02:19:20 -07:00
|
|
|
"io/ioutil"
|
2010-02-26 00:39:43 -07:00
|
|
|
"json"
|
2010-03-10 02:19:20 -07:00
|
|
|
"os"
|
2011-01-12 01:25:17 -07:00
|
|
|
"strings"
|
2009-12-15 16:41:46 -07:00
|
|
|
"testing"
|
2009-04-08 23:08:55 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
type Test struct {
|
2009-12-15 16:41:46 -07:00
|
|
|
in, out, err string
|
2009-04-08 23:08:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type T struct {
|
2011-01-11 16:47:45 -07:00
|
|
|
Item string
|
|
|
|
Value string
|
2009-04-08 23:08:55 -06:00
|
|
|
}
|
|
|
|
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
type U struct {
|
2011-01-11 16:47:45 -07:00
|
|
|
Mp map[string]int
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
}
|
|
|
|
|
2009-04-08 23:08:55 -06:00
|
|
|
type S struct {
|
2011-01-11 16:47:45 -07:00
|
|
|
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
|
|
|
|
JSON interface{}
|
|
|
|
Innermap U
|
|
|
|
Stringmap map[string]string
|
|
|
|
Bytes []byte
|
|
|
|
Iface interface{}
|
|
|
|
Ifaceptr interface{}
|
2009-04-08 23:08:55 -06:00
|
|
|
}
|
|
|
|
|
2011-01-11 16:47:45 -07:00
|
|
|
func (s *S) PointerMethod() string { return "ptrmethod!" }
|
2009-12-16 04:10:50 -07:00
|
|
|
|
2011-01-11 16:47:45 -07:00
|
|
|
func (s S) ValueMethod() string { return "valmethod!" }
|
2009-12-16 04:10:50 -07:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var t1 = T{"ItemNumber1", "ValueNumber1"}
|
|
|
|
var t2 = T{"ItemNumber2", "ValueNumber2"}
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-04-13 20:29:38 -06:00
|
|
|
func uppercase(v interface{}) string {
|
2009-12-15 16:41:46 -07:00
|
|
|
s := v.(string)
|
|
|
|
t := ""
|
2009-04-09 00:33:31 -06:00
|
|
|
for i := 0; i < len(s); i++ {
|
2009-12-15 16:41:46 -07:00
|
|
|
c := s[i]
|
2009-04-09 00:33:31 -06:00
|
|
|
if 'a' <= c && c <= 'z' {
|
2009-11-09 22:23:52 -07:00
|
|
|
c = c + 'A' - 'a'
|
2009-04-09 00:33:31 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
t += string(c)
|
2009-04-09 00:33:31 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
return t
|
2009-04-09 00:33:31 -06:00
|
|
|
}
|
|
|
|
|
2009-04-13 20:29:38 -06:00
|
|
|
func plus1(v interface{}) string {
|
2009-12-15 16:41:46 -07:00
|
|
|
i := v.(int)
|
|
|
|
return fmt.Sprint(i + 1)
|
2009-04-09 00:33:31 -06:00
|
|
|
}
|
|
|
|
|
2010-12-01 14:33:49 -07:00
|
|
|
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]))
|
2009-11-09 13:07:39 -07:00
|
|
|
}
|
2009-04-13 20:29:38 -06:00
|
|
|
}
|
|
|
|
|
2010-12-01 18:10:40 -07:00
|
|
|
func multiword(w io.Writer, format string, value ...interface{}) {
|
|
|
|
for _, v := range value {
|
|
|
|
fmt.Fprintf(w, "<%v>", v)
|
|
|
|
}
|
|
|
|
}
|
2009-04-13 20:29:38 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var formatters = FormatterMap{
|
|
|
|
"uppercase": writer(uppercase),
|
2010-03-02 14:46:51 -07:00
|
|
|
"+1": writer(plus1),
|
2010-12-01 18:10:40 -07:00
|
|
|
"multiword": multiword,
|
2009-04-09 00:33:31 -06:00
|
|
|
}
|
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var tests = []*Test{
|
2009-04-08 23:08:55 -06:00
|
|
|
// Simple
|
2009-10-08 16:14:54 -06:00
|
|
|
&Test{"", "", ""},
|
2010-01-07 23:49:55 -07:00
|
|
|
&Test{"abc", "abc", ""},
|
2009-10-08 16:14:54 -06:00
|
|
|
&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", "", ""},
|
2010-08-16 17:44:16 -06:00
|
|
|
&Test{"\tSome Text\t\n", "\tSome Text\t\n", ""},
|
2010-08-27 15:52:55 -06:00
|
|
|
&Test{" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""},
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-04-20 19:51:13 -06:00
|
|
|
// Variables at top level
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{Header}={Integer}\n",
|
2009-04-20 19:51:13 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "Header=77\n",
|
2009-04-20 19:51:13 -06:00
|
|
|
},
|
|
|
|
|
2009-12-16 04:10:50 -07:00
|
|
|
// Method at top level
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "ptrmethod={PointerMethod}\n",
|
2009-12-16 04:10:50 -07:00
|
|
|
|
|
|
|
out: "ptrmethod=ptrmethod!\n",
|
|
|
|
},
|
|
|
|
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "valmethod={ValueMethod}\n",
|
2009-12-16 04:10:50 -07:00
|
|
|
|
|
|
|
out: "valmethod=valmethod!\n",
|
|
|
|
},
|
|
|
|
|
2009-04-08 23:08:55 -06:00
|
|
|
// Section
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Data }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"some text for the section\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "some text for the section\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Data }\n" +
|
|
|
|
"{Header}={Integer}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "Header=77\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
|
|
|
"{Header}={Integer}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "Header=77\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"data present\n" +
|
|
|
|
"{.or}\n" +
|
|
|
|
"data not present\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "data present\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Empty }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"data present\n" +
|
|
|
|
"{.or}\n" +
|
|
|
|
"data not present\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "data not present\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Null }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"data present\n" +
|
|
|
|
"{.or}\n" +
|
|
|
|
"data not present\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "data not present\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
|
|
|
"{Header}={Integer}\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.section @ }\n" +
|
2011-01-11 16:47:45 -07:00
|
|
|
"{Header}={Integer}\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.end}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "Header=77\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"Header=77\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
2010-01-07 23:49:55 -07:00
|
|
|
|
2009-04-14 01:06:49 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Data}{.end} {Header}\n",
|
2009-04-14 01:06:49 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: " Header\n",
|
2009-04-14 01:06:49 -06:00
|
|
|
},
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2010-12-20 14:36:47 -07:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Integer}{@}{.end}",
|
2010-12-20 14:36:47 -07:00
|
|
|
|
|
|
|
out: "77",
|
|
|
|
},
|
|
|
|
|
2011-01-11 16:47:45 -07:00
|
|
|
|
2009-04-08 23:08:55 -06:00
|
|
|
// Repeated
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.repeated section @ }\n" +
|
2011-01-11 16:47:45 -07:00
|
|
|
"{Item}={Value}\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.end}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "ItemNumber1=ValueNumber1\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"ItemNumber2=ValueNumber2\n",
|
2009-04-08 23:08:55 -06:00
|
|
|
},
|
2009-04-20 19:51:13 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.repeated section @ }\n" +
|
2011-01-11 16:47:45 -07:00
|
|
|
"{Item}={Value}\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.or}\n" +
|
|
|
|
"this should not appear\n" +
|
|
|
|
"{.end}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-20 19:51:13 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "ItemNumber1=ValueNumber1\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"ItemNumber2=ValueNumber2\n",
|
2009-04-20 19:51:13 -06:00
|
|
|
},
|
|
|
|
&Test{
|
2009-12-09 17:54:07 -07:00
|
|
|
in: "{.section @ }\n" +
|
2011-01-11 16:47:45 -07:00
|
|
|
"{.repeated section Empty }\n" +
|
|
|
|
"{Item}={Value}\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.or}\n" +
|
|
|
|
"this should appear: empty field\n" +
|
|
|
|
"{.end}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-20 19:51:13 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "this should appear: empty field\n",
|
2009-04-20 19:51:13 -06:00
|
|
|
},
|
2009-08-29 22:13:32 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Pdata }\n" +
|
|
|
|
"{Item}\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.alternates with}\n" +
|
|
|
|
"is\nover\nmultiple\nlines\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-08-29 22:13:32 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "ItemNumber1\n" +
|
|
|
|
"is\nover\nmultiple\nlines\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"ItemNumber2\n",
|
2009-08-29 22:13:32 -06:00
|
|
|
},
|
2010-01-07 23:49:55 -07:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Pdata }\n" +
|
|
|
|
"{Item}\n" +
|
2010-01-07 23:49:55 -07:00
|
|
|
"{.alternates with}\n" +
|
|
|
|
"is\nover\nmultiple\nlines\n" +
|
|
|
|
" {.end}\n",
|
|
|
|
|
|
|
|
out: "ItemNumber1\n" +
|
|
|
|
"is\nover\nmultiple\nlines\n" +
|
|
|
|
"ItemNumber2\n",
|
|
|
|
},
|
2009-04-27 22:04:46 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.repeated section @ }\n" +
|
2011-01-11 16:47:45 -07:00
|
|
|
"{Item}={Value}\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{.alternates with}DIVIDER\n" +
|
|
|
|
"{.or}\n" +
|
|
|
|
"this should not appear\n" +
|
|
|
|
"{.end}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-27 22:04:46 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "ItemNumber1=ValueNumber1\n" +
|
|
|
|
"DIVIDER\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"ItemNumber2=ValueNumber2\n",
|
2009-04-27 22:04:46 -06:00
|
|
|
},
|
2009-08-26 19:30:13 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Vec }\n" +
|
2009-12-09 17:54:07 -07:00
|
|
|
"{@}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-08-26 19:30:13 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "elt1\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"elt2\n",
|
2009-08-26 19:30:13 -06:00
|
|
|
},
|
2010-01-07 23:49:55 -07:00
|
|
|
// Same but with a space before {.end}: was a bug.
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Vec }\n" +
|
2010-01-07 23:49:55 -07:00
|
|
|
"{@} {.end}\n",
|
|
|
|
|
|
|
|
out: "elt1 elt2 \n",
|
|
|
|
},
|
2009-08-26 19:30:13 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Integer}{.end}",
|
2009-08-26 19:30:13 -06:00
|
|
|
|
2011-01-11 16:47:45 -07:00
|
|
|
err: "line 1: .repeated: cannot repeat Integer (type int)",
|
2009-08-26 19:30:13 -06:00
|
|
|
},
|
2009-04-09 00:33:31 -06:00
|
|
|
|
2009-07-30 19:17:07 -06:00
|
|
|
// Nested names
|
|
|
|
&Test{
|
2009-12-09 17:54:07 -07:00
|
|
|
in: "{.section @ }\n" +
|
2011-01-11 16:47:45 -07:00
|
|
|
"{InnerT.Item}={InnerT.Value}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}",
|
2009-07-30 19:17:07 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "ItemNumber1=ValueNumber1\n",
|
2009-07-30 19:17:07 -06:00
|
|
|
},
|
2009-09-01 17:31:49 -06:00
|
|
|
&Test{
|
2009-12-09 17:54:07 -07:00
|
|
|
in: "{.section @ }\n" +
|
2011-01-11 16:47:45 -07:00
|
|
|
"{InnerT.Item}={.section InnerT}{.section Value}{@}{.end}{.end}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}",
|
2009-09-01 17:31:49 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "ItemNumber1=ValueNumber1\n",
|
2009-09-01 17:31:49 -06:00
|
|
|
},
|
|
|
|
|
2009-07-30 19:17:07 -06:00
|
|
|
|
2009-04-09 00:33:31 -06:00
|
|
|
// Formatters
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
|
|
|
"{Header|uppercase}={Integer|+1}\n" +
|
|
|
|
"{Header|html}={Integer|str}\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"{.end}\n",
|
2009-04-09 00:33:31 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "HEADER=78\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"Header=77\n",
|
2009-04-09 00:33:31 -06:00
|
|
|
},
|
2009-04-15 01:26:49 -06:00
|
|
|
|
2010-12-01 18:10:40 -07:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Pdata }\n" +
|
|
|
|
"{Header|uppercase}={Integer Header|multiword}\n" +
|
|
|
|
"{Header|html}={Header Integer|multiword}\n" +
|
|
|
|
"{Header|html}={Header Integer}\n" +
|
2010-12-01 18:10:40 -07:00
|
|
|
"{.end}\n",
|
|
|
|
|
|
|
|
out: "HEADER=<77><Header>\n" +
|
|
|
|
"Header=<Header><77>\n" +
|
|
|
|
"Header=Header77\n",
|
|
|
|
},
|
|
|
|
|
2009-04-15 01:05:47 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{Raw}\n" +
|
|
|
|
"{Raw|html}\n",
|
2009-04-15 01:26:49 -06:00
|
|
|
|
2009-12-09 17:54:07 -07:00
|
|
|
out: "&<>!@ #$%^\n" +
|
2009-11-05 16:12:37 -07:00
|
|
|
"&<>!@ #$%^\n",
|
2009-04-15 01:05:47 -06:00
|
|
|
},
|
2009-04-15 01:26:49 -06:00
|
|
|
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Emptystring}emptystring{.end}\n" +
|
|
|
|
"{.section Header}header{.end}\n",
|
2009-04-15 01:26:49 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "\nheader\n",
|
2009-04-15 01:26:49 -06:00
|
|
|
},
|
2009-09-01 17:31:49 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section True}1{.or}2{.end}\n" +
|
|
|
|
"{.section False}3{.or}4{.end}\n",
|
2009-09-01 17:31:49 -06:00
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
out: "1\n4\n",
|
2009-09-01 17:31:49 -06:00
|
|
|
},
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
|
2009-11-30 11:29:14 -07:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{Bytes}",
|
2009-11-30 11:29:14 -07:00
|
|
|
|
|
|
|
out: "hello",
|
|
|
|
},
|
|
|
|
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
// Maps
|
|
|
|
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{Mp.mapkey}\n",
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
|
|
|
|
out: "Ahoy!\n",
|
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{Innermap.Mp.innerkey}\n",
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
|
|
|
|
out: "55\n",
|
|
|
|
},
|
2010-02-26 00:39:43 -07:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Innermap}{.section Mp}{innerkey}{.end}{.end}\n",
|
2010-02-26 00:39:43 -07:00
|
|
|
|
|
|
|
out: "55\n",
|
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section JSON}{.repeated section maps}{a}{b}{.end}{.end}\n",
|
2010-02-26 00:39:43 -07:00
|
|
|
|
|
|
|
out: "1234\n",
|
|
|
|
},
|
2009-12-23 13:41:56 -07:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{Stringmap.stringkey1}\n",
|
2009-12-23 13:41:56 -07:00
|
|
|
|
|
|
|
out: "stringresult\n",
|
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Stringmap}\n" +
|
2009-12-23 13:41:56 -07:00
|
|
|
"{@}\n" +
|
|
|
|
"{.end}",
|
|
|
|
|
|
|
|
out: "stringresult\n" +
|
|
|
|
"stringresult\n",
|
|
|
|
},
|
2010-08-17 07:13:07 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Stringmap}\n" +
|
2010-08-17 07:13:07 -06:00
|
|
|
"\t{@}\n" +
|
|
|
|
"{.end}",
|
|
|
|
|
|
|
|
out: "\tstringresult\n" +
|
|
|
|
"\tstringresult\n",
|
|
|
|
},
|
2010-01-15 14:49:31 -07:00
|
|
|
|
|
|
|
// Interface values
|
|
|
|
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{Iface}",
|
2010-01-15 14:49:31 -07:00
|
|
|
|
|
|
|
out: "[1 2 3]",
|
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.repeated section Iface}{@}{.alternates with} {.end}",
|
2010-01-15 14:49:31 -07:00
|
|
|
|
|
|
|
out: "1 2 3",
|
|
|
|
},
|
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Iface}{@}{.end}",
|
2010-01-15 14:49:31 -07:00
|
|
|
|
|
|
|
out: "[1 2 3]",
|
|
|
|
},
|
2010-04-26 11:01:13 -06:00
|
|
|
&Test{
|
2011-01-11 16:47:45 -07:00
|
|
|
in: "{.section Ifaceptr}{Item} {Value}{.end}",
|
2010-04-26 11:01:13 -06:00
|
|
|
|
|
|
|
out: "Item Value",
|
|
|
|
},
|
2009-04-08 23:08:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAll(t *testing.T) {
|
2010-03-10 02:19:20 -07:00
|
|
|
// Parse
|
|
|
|
testAll(t, func(test *Test) (*Template, os.Error) { return Parse(test.in, formatters) })
|
|
|
|
// ParseFile
|
|
|
|
testAll(t, func(test *Test) (*Template, os.Error) {
|
2010-08-10 22:04:03 -06:00
|
|
|
err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
|
|
|
|
if err != nil {
|
|
|
|
t.Error("unexpected write error:", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
2010-03-10 02:19:20 -07:00
|
|
|
return ParseFile("_test/test.tmpl", formatters)
|
|
|
|
})
|
2010-08-10 22:04:03 -06:00
|
|
|
// 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")
|
|
|
|
})
|
2010-03-10 02:19:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
|
2009-12-15 16:41:46 -07:00
|
|
|
s := new(S)
|
2009-04-08 23:08:55 -06:00
|
|
|
// initialized by hand for clarity.
|
2011-01-11 16:47:45 -07:00
|
|
|
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!"
|
|
|
|
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.Bytes = []byte("hello")
|
|
|
|
s.Iface = []int{1, 2, 3}
|
|
|
|
s.Ifaceptr = &T{"Item", "Value"}
|
2009-12-15 16:41:46 -07:00
|
|
|
|
|
|
|
var buf bytes.Buffer
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, test := range tests {
|
2009-12-15 16:41:46 -07:00
|
|
|
buf.Reset()
|
2010-03-10 02:19:20 -07:00
|
|
|
tmpl, err := parseFunc(test)
|
2009-04-14 01:06:49 -06:00
|
|
|
if err != nil {
|
2010-08-17 07:13:07 -06:00
|
|
|
t.Error("unexpected parse error: ", err)
|
2009-12-15 16:41:46 -07:00
|
|
|
continue
|
2009-04-14 01:06:49 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
err = tmpl.Execute(s, &buf)
|
2009-08-26 19:30:13 -06:00
|
|
|
if test.err == "" {
|
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Error("unexpected execute error:", err)
|
2009-08-26 19:30:13 -06:00
|
|
|
}
|
|
|
|
} else {
|
2010-01-07 23:49:55 -07:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expected execute error %q, got nil", test.err)
|
|
|
|
} else if err.String() != test.err {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("expected execute error %q, got %q", test.err, err.String())
|
2009-08-26 19:30:13 -06:00
|
|
|
}
|
2009-04-08 23:08:55 -06:00
|
|
|
}
|
2009-09-18 00:51:06 -06:00
|
|
|
if buf.String() != test.out {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("for %q: expected %q got %q", test.in, test.out, buf.String())
|
2009-04-08 23:08:55 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
func TestMapDriverType(t *testing.T) {
|
2009-12-15 16:41:46 -07:00
|
|
|
mp := map[string]string{"footer": "Ahoy!"}
|
|
|
|
tmpl, err := Parse("template: {footer}", nil)
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Error("unexpected parse error:", err)
|
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
var b bytes.Buffer
|
|
|
|
err = tmpl.Execute(mp, &b)
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Error("unexpected execute error:", err)
|
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
s := b.String()
|
|
|
|
expected := "template: Ahoy!"
|
Map support for template.Execute().
Allows the developer to pass a map either by itself for
evaluation, or inside a struct. Access to data inside
maps is identical to the current system for structs, ie.
-Psuedocode-
mp map[string]string = {
"header" : "A fantastic header!",
"footer" : "A not-so-fantastic footer!",
}
template.Execute(mp)
...can be accessed using {header} and {footer} in
the template. Similarly, for maps inside structs:
type s struct {
mp map[string]string,
}
s1 = new s
s1.mp["header"] = "A fantastic header!";
template.Execute(s1)
...is accessed using {mp.header}. Multi-maps, ie.
map[string](map[string]string) and maps of structs
containing more maps are unsupported, but then, I'm
not even sure if that's supported by the language.
Map elements can be of any type that can be written
by the formatters. Keys should really only be strings.
Fixes #259.
R=r, rsc
https://golang.org/cl/157088
2009-11-19 22:08:05 -07:00
|
|
|
if s != expected {
|
|
|
|
t.Errorf("failed passing string as data: expected %q got %q", "template: Ahoy!", s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-14 02:12:20 -06:00
|
|
|
func TestStringDriverType(t *testing.T) {
|
2009-12-15 16:41:46 -07:00
|
|
|
tmpl, err := Parse("template: {@}", nil)
|
2009-04-14 01:06:49 -06:00
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Error("unexpected parse error:", err)
|
2009-04-14 01:06:49 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
var b bytes.Buffer
|
|
|
|
err = tmpl.Execute("hello", &b)
|
2009-04-14 22:25:33 -06:00
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Error("unexpected execute error:", err)
|
2009-04-14 22:25:33 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
s := b.String()
|
2009-04-14 02:12:20 -06:00
|
|
|
if s != "template: hello" {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s)
|
2009-04-08 23:08:55 -06:00
|
|
|
}
|
|
|
|
}
|
2009-04-14 22:25:33 -06:00
|
|
|
|
|
|
|
func TestTwice(t *testing.T) {
|
2009-12-15 16:41:46 -07:00
|
|
|
tmpl, err := Parse("template: {@}", nil)
|
2009-04-14 22:25:33 -06:00
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Error("unexpected parse error:", err)
|
2009-04-14 22:25:33 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
var b bytes.Buffer
|
|
|
|
err = tmpl.Execute("hello", &b)
|
2009-04-14 22:25:33 -06:00
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Error("unexpected parse error:", err)
|
2009-04-14 22:25:33 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
s := b.String()
|
|
|
|
text := "template: hello"
|
2009-04-14 22:25:33 -06:00
|
|
|
if s != text {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("failed passing string as data: expected %q got %q", text, s)
|
2009-04-14 22:25:33 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
err = tmpl.Execute("hello", &b)
|
2009-04-14 22:25:33 -06:00
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Error("unexpected parse error:", err)
|
2009-04-14 22:25:33 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
s = b.String()
|
|
|
|
text += text
|
2009-04-14 22:25:33 -06:00
|
|
|
if s != text {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("failed passing string as data: expected %q got %q", text, s)
|
2009-04-14 22:25:33 -06:00
|
|
|
}
|
|
|
|
}
|
2009-04-14 23:35:18 -06:00
|
|
|
|
|
|
|
func TestCustomDelims(t *testing.T) {
|
|
|
|
// try various lengths. zero should catch error.
|
|
|
|
for i := 0; i < 7; i++ {
|
|
|
|
for j := 0; j < 7; j++ {
|
2009-12-15 16:41:46 -07:00
|
|
|
tmpl := New(nil)
|
2009-04-14 23:35:18 -06:00
|
|
|
// first two chars deliberately the same to test equal left and right delims
|
2009-12-15 16:41:46 -07:00
|
|
|
ldelim := "$!#$%^&"[0:i]
|
|
|
|
rdelim := "$*&^%$!"[0:j]
|
|
|
|
tmpl.SetDelims(ldelim, rdelim)
|
2009-04-14 23:35:18 -06:00
|
|
|
// if braces, this would be template: {@}{.meta-left}{.meta-right}
|
|
|
|
text := "template: " +
|
|
|
|
ldelim + "@" + rdelim +
|
|
|
|
ldelim + ".meta-left" + rdelim +
|
2009-12-15 16:41:46 -07:00
|
|
|
ldelim + ".meta-right" + rdelim
|
|
|
|
err := tmpl.Parse(text)
|
2009-04-14 23:35:18 -06:00
|
|
|
if err != nil {
|
2009-12-15 16:41:46 -07:00
|
|
|
if i == 0 || j == 0 { // expected
|
2009-11-09 13:07:39 -07:00
|
|
|
continue
|
2009-04-14 23:35:18 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
t.Error("unexpected parse error:", err)
|
2009-04-14 23:35:18 -06:00
|
|
|
} else if i == 0 || j == 0 {
|
2009-12-15 16:41:46 -07:00
|
|
|
t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
|
|
|
|
continue
|
2009-04-14 23:35:18 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
var b bytes.Buffer
|
|
|
|
err = tmpl.Execute("hello", &b)
|
|
|
|
s := b.String()
|
2009-11-09 22:23:52 -07:00
|
|
|
if s != "template: hello"+ldelim+rdelim {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
|
2009-04-14 23:35:18 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-07-31 13:52:03 -06:00
|
|
|
|
|
|
|
// Test that a variable evaluates to the field itself and does not further indirection
|
|
|
|
func TestVarIndirection(t *testing.T) {
|
2009-12-15 16:41:46 -07:00
|
|
|
s := new(S)
|
2009-07-31 13:52:03 -06:00
|
|
|
// initialized by hand for clarity.
|
2011-01-11 16:47:45 -07:00
|
|
|
s.InnerPointerT = &t1
|
2009-07-31 13:52:03 -06:00
|
|
|
|
2009-12-15 16:41:46 -07:00
|
|
|
var buf bytes.Buffer
|
2011-01-11 16:47:45 -07:00
|
|
|
input := "{.section @}{InnerPointerT}{.end}"
|
2009-12-15 16:41:46 -07:00
|
|
|
tmpl, err := Parse(input, nil)
|
2009-07-31 13:52:03 -06:00
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Fatal("unexpected parse error:", err)
|
2009-07-31 13:52:03 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
err = tmpl.Execute(s, &buf)
|
2009-07-31 13:52:03 -06:00
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Fatal("unexpected execute error:", err)
|
2009-07-31 13:52:03 -06:00
|
|
|
}
|
2009-12-15 16:41:46 -07:00
|
|
|
expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
|
2009-09-18 00:51:06 -06:00
|
|
|
if buf.String() != expect {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
|
2009-07-31 13:52:03 -06:00
|
|
|
}
|
|
|
|
}
|
2010-03-18 16:46:39 -06:00
|
|
|
|
|
|
|
func TestHTMLFormatterWithByte(t *testing.T) {
|
|
|
|
s := "Test string."
|
|
|
|
b := []byte(s)
|
|
|
|
var buf bytes.Buffer
|
2010-12-01 14:33:49 -07:00
|
|
|
HTMLFormatter(&buf, "", b)
|
2010-03-18 16:46:39 -06:00
|
|
|
bs := buf.String()
|
|
|
|
if bs != s {
|
|
|
|
t.Errorf("munged []byte, expected: %s got: %s", s, bs)
|
|
|
|
}
|
|
|
|
}
|
2011-01-12 01:25:17 -07:00
|
|
|
|
|
|
|
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(u, &buf)
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|