package raymond
import "testing"
var evalTests = []Test{
{
"only content",
"this is content",
nil, nil, nil, nil,
"this is content",
},
{
"checks path in parent contexts",
"{{#a}}{{one}}{{#b}}{{one}}{{two}}{{one}}{{/b}}{{/a}}",
map[string]interface{}{"a": map[string]int{"one": 1}, "b": map[string]int{"two": 2}},
nil, nil, nil,
"1121",
},
{
"block params",
"{{#foo as |bar|}}{{bar}}{{/foo}}{{bar}}",
map[string]string{"foo": "baz", "bar": "bat"},
nil, nil, nil,
"bazbat",
},
{
"block params on array",
"{{#foo as |bar i|}}{{i}}.{{bar}} {{/foo}}",
map[string][]string{"foo": {"baz", "bar", "bat"}},
nil, nil, nil,
"0.baz 1.bar 2.bat ",
},
{
"nested block params",
"{{#foos as |foo iFoo|}}{{#wats as |wat iWat|}}{{iFoo}}.{{iWat}}.{{foo}}-{{wat}} {{/wats}}{{/foos}}",
map[string][]string{"foos": {"baz", "bar"}, "wats": {"the", "phoque"}},
nil, nil, nil,
"0.0.baz-the 0.1.baz-phoque 1.0.bar-the 1.1.bar-phoque ",
},
{
"block params with path reference",
"{{#foo as |bar|}}{{bar.baz}}{{/foo}}",
map[string]map[string]string{"foo": {"baz": "bat"}},
nil, nil, nil,
"bat",
},
{
"falsy block evaluation",
"{{#foo}}bar{{/foo}} baz",
map[string]interface{}{"foo": false},
nil, nil, nil,
" baz",
},
{
"block helper returns a SafeString",
"{{title}} - {{#bold}}{{body}}{{/bold}}",
map[string]string{
"title": "My new blog post",
"body": "I have so many things to say!",
},
nil,
map[string]interface{}{"bold": func(options *Options) SafeString {
return SafeString(`
` + options.Fn() + "
")
}},
nil,
`My new blog post - I have so many things to say!
`,
},
{
"chained blocks",
"{{#if a}}A{{else if b}}B{{else}}C{{/if}}",
map[string]interface{}{"b": false},
nil, nil, nil,
"C",
},
// @todo Test with a "../../path" (depth 2 path) while context is only depth 1
}
func TestEval(t *testing.T) {
t.Parallel()
launchTests(t, evalTests)
}
var evalErrors = []Test{
{
"functions with wrong number of arguments",
`{{foo "bar"}}`,
map[string]interface{}{"foo": func(a string, b string) string { return "foo" }},
nil, nil, nil,
"Helper 'foo' called with wrong number of arguments, needed 2 but got 1",
},
{
"functions with wrong number of returned values (1)",
"{{foo}}",
map[string]interface{}{"foo": func() {}},
nil, nil, nil,
"Helper function must return a string or a SafeString",
},
{
"functions with wrong number of returned values (2)",
"{{foo}}",
map[string]interface{}{"foo": func() (string, bool, string) { return "foo", true, "bar" }},
nil, nil, nil,
"Helper function must return a string or a SafeString",
},
}
func TestEvalErrors(t *testing.T) {
launchErrorTests(t, evalErrors)
}
func TestEvalStruct(t *testing.T) {
t.Parallel()
source := `
By {{author.FirstName}} {{Author.lastName}}
{{Body}}
Comments
{{#each comments}}
By {{Author.FirstName}} {{author.LastName}}
{{body}}
{{/each}}
`
expected := `
By Jean Valjean
Life is difficult
Comments
By Marcel Beliveau
LOL!
`
type Person struct {
FirstName string
LastName string
}
type Comment struct {
Author Person
Body string
}
type Post struct {
Author Person
Body string
Comments []Comment
}
ctx := Post{
Person{"Jean", "Valjean"},
"Life is difficult",
[]Comment{
Comment{
Person{"Marcel", "Beliveau"},
"LOL!",
},
},
}
output := MustRender(source, ctx)
if output != expected {
t.Errorf("Failed to evaluate with struct context")
}
}
type TestFoo struct {
}
func (t *TestFoo) Subject() string {
return "foo"
}
func TestEvalMethod(t *testing.T) {
t.Parallel()
source := `Subject is {{subject}}! YES I SAID {{Subject}}!`
expected := `Subject is foo! YES I SAID foo!`
ctx := &TestFoo{}
output := MustRender(source, ctx)
if output != expected {
t.Errorf("Failed to evaluate struct method: %s", output)
}
}
type TestBar struct {
}
func (t *TestBar) Subject() interface{} {
return testBar
}
func testBar() string {
return "bar"
}
func TestEvalMethodReturningFunc(t *testing.T) {
t.Parallel()
source := `Subject is {{subject}}! YES I SAID {{Subject}}!`
expected := `Subject is bar! YES I SAID bar!`
ctx := &TestBar{}
output := MustRender(source, ctx)
if output != expected {
t.Errorf("Failed to evaluate struct method: %s", output)
}
}