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) } }