mirror of
https://github.com/danog/liquid.git
synced 2024-11-26 21:24:40 +01:00
2e107bef29
Sometimes a consumer of a template needs to know what objects were used. In my case, a template can reference secret values from a secret store vault and instead of passing all possible secrets to the template only to render two of them, we use the ast to determine which are used and only retrieve those values from the vault before rendering the template. Exposing the ast allows us to use the liquid APIs just like normal, without having to jump through hoops to build the ast ourselves using the other types exported in this library. Signed-off-by: Carolyn Van Slyck <me@carolynvanslyck.com>
118 lines
2.8 KiB
Go
118 lines
2.8 KiB
Go
package liquid
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/osteele/liquid/render"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestTemplate_GetRoot(t *testing.T) {
|
|
root := &render.SeqNode{}
|
|
tmpl := Template{root: root}
|
|
require.Same(t, root, tmpl.GetRoot())
|
|
}
|
|
|
|
func TestTemplate_RenderString(t *testing.T) {
|
|
engine := NewEngine()
|
|
tpl, err := engine.ParseTemplate([]byte(`{{ "hello world" | capitalize }}`))
|
|
require.NoError(t, err)
|
|
out, err := tpl.RenderString(testBindings)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Hello world", out)
|
|
}
|
|
|
|
func TestTemplate_SetSourcePath(t *testing.T) {
|
|
engine := NewEngine()
|
|
engine.RegisterTag("sourcepath", func(c render.Context) (string, error) {
|
|
return c.SourceFile(), nil
|
|
})
|
|
tpl, err := engine.ParseTemplateLocation([]byte(`{% sourcepath %}`), "source.md", 1)
|
|
require.NoError(t, err)
|
|
out, err := tpl.RenderString(testBindings)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "source.md", out)
|
|
|
|
src := []byte(`{{ n | undefined_filter }}`)
|
|
t1, err := engine.ParseTemplateLocation(src, "path1", 1)
|
|
require.NoError(t, err)
|
|
t2, err := engine.ParseTemplateLocation(src, "path2", 1)
|
|
require.NoError(t, err)
|
|
_, err = t1.Render(Bindings{})
|
|
require.Error(t, err)
|
|
require.Equal(t, "path1", err.Path())
|
|
_, err = t2.Render(Bindings{})
|
|
require.Error(t, err)
|
|
require.Equal(t, "path2", err.Path())
|
|
}
|
|
|
|
func TestTemplate_Parse_race(t *testing.T) {
|
|
var (
|
|
engine = NewEngine()
|
|
count = 10
|
|
wg sync.WaitGroup
|
|
)
|
|
for i := 0; i < count; i++ {
|
|
wg.Add(1)
|
|
go func(i int) {
|
|
path := fmt.Sprintf("path %d", i)
|
|
_, err := engine.ParseTemplateLocation([]byte("{{ syntax error }}"), path, i)
|
|
require.Error(t, err)
|
|
require.Equal(t, path, err.Path())
|
|
wg.Done()
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
}
|
|
|
|
func TestTemplate_Render_race(t *testing.T) {
|
|
src := []byte(`{{ n | undefined_filter }}`)
|
|
engine := NewEngine()
|
|
|
|
var (
|
|
count = 10
|
|
paths = make([]string, count)
|
|
ts = make([]*Template, count)
|
|
wg sync.WaitGroup
|
|
)
|
|
for i := 0; i < count; i++ {
|
|
paths[i] = fmt.Sprintf("path %d", i)
|
|
wg.Add(1)
|
|
go func(i int) {
|
|
defer wg.Done()
|
|
var err error
|
|
ts[i], err = engine.ParseTemplateLocation(src, paths[i], i)
|
|
require.NoError(t, err)
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
|
|
var wg2 sync.WaitGroup
|
|
for i := 0; i < count; i++ {
|
|
wg2.Add(1)
|
|
go func(i int) {
|
|
defer wg2.Done()
|
|
_, err := ts[i].Render(Bindings{})
|
|
require.Error(t, err)
|
|
require.Equal(t, paths[i], err.Path())
|
|
}(i)
|
|
}
|
|
wg2.Wait()
|
|
}
|
|
|
|
func BenchmarkTemplate_Render(b *testing.B) {
|
|
engine := NewEngine()
|
|
bindings := Bindings{"a": "string value"}
|
|
tpl, err := engine.ParseString(`{% for i in (1..1000) %}{% if i > 500 %}{{a}}{% else %}0{% endif %}{% endfor %}`)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := tpl.Render(bindings)
|
|
require.NoError(b, err)
|
|
}
|
|
}
|