Skip to content

Commit

Permalink
Coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
osteele committed Jul 19, 2017
1 parent 7af399a commit 413b328
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 30 deletions.
1 change: 1 addition & 0 deletions cmd/liquid/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func run(args []string) error {
case args[0] == "-h" || args[0] == "--help":
usage()
case strings.HasPrefix(args[0], "-"):
// undefined flag
usage()
exit(1)
case len(args) == 1:
Expand Down
12 changes: 11 additions & 1 deletion cmd/liquid/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,36 @@ import (
func TestMain(t *testing.T) {
exit = func(n int) { t.Fatalf("exit called") }

// stdin
src := `{{ "Hello World" | downcase | split: " " | first | append: "!"}}`
buf := new(bytes.Buffer)
stdin = bytes.NewBufferString(src)
stdout = buf
require.NoError(t, run([]string{}))
require.Equal(t, "hello!", buf.String())

// filename
buf = new(bytes.Buffer)
stdin = bytes.NewBufferString("")
stdout = buf
require.NoError(t, run([]string{"testdata/source.txt"}))
require.Contains(t, buf.String(), "file system")

// --help
buf = new(bytes.Buffer)
stdout = buf
require.NoError(t, run([]string{"--help"}))
require.Contains(t, buf.String(), "usage:")

// --undefined-flag
exitCode := 0
exit = func(n int) { exitCode = n }
require.NoError(t, run([]string{"--unknown-flag"}))
require.NoError(t, run([]string{"--undefined-flag"}))
require.Equal(t, 1, exitCode)

// multiple args
exitCode = 0
exit = func(n int) { exitCode = n }
require.NoError(t, run([]string{"file1", "file2"}))
require.Equal(t, 1, exitCode)
}
1 change: 1 addition & 0 deletions expressions/filters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func TestContext_AddFilter(t *testing.T) {
require.Panics(t, func() { cfg.AddFilter("f", func(int) {}) })
// require.Panics(t, func() { cfg.AddFilter("f", func(int) (a int, b int) { return }) })
require.Panics(t, func() { cfg.AddFilter("f", func(int) (a int, e error, b int) { return }) })
require.Panics(t, func() { cfg.AddFilter("f", 10) })
}

func TestContext_runFilter(t *testing.T) {
Expand Down
21 changes: 18 additions & 3 deletions expressions/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@ var parseTests = []struct {
in string
expect interface{}
}{
{`a | filter: b`, 3},
{`true`, true},
{`false`, false},
{`nil`, nil},
{`2`, 2},
{`"s"`, "s"},
{`a`, 1},
{`obj.prop`, 2},
{`a | add: b`, 3},
{`1 == 1`, true},
{`1 != 1`, false},
{`true and true`, true},
}

var parseErrorTests = []struct{ in, expected string }{
Expand All @@ -23,10 +33,15 @@ var parseErrorTests = []struct{ in, expected string }{
{`%when a b`, "syntax error"},
}

// Since the parser returns funcs, there's no easy way to test them except evaluation
func TestParse(t *testing.T) {
cfg := NewConfig()
cfg.AddFilter("filter", func(a, b int) int { return a + b })
ctx := NewContext(map[string]interface{}{"a": 1, "b": 2}, cfg)
cfg.AddFilter("add", func(a, b int) int { return a + b })
ctx := NewContext(map[string]interface{}{
"a": 1,
"b": 2,
"obj": map[string]int{"prop": 2},
}, cfg)
for i, test := range parseTests {
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
expr, err := Parse(test.in)
Expand Down
24 changes: 24 additions & 0 deletions render/blocks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package render

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestBlockSyntax(t *testing.T) {
cfg := NewConfig()
cfg.AddBlock("if").Clause("else")
cfg.AddBlock("case").Clause("else")
cfg.AddBlock("unless")

require.Panics(t, func() { cfg.AddBlock("if") })

g := cfg.grammar
ifBlock, _ := g.findBlockDef("if")
elseBlock, _ := g.findBlockDef("else")
unlessBlock, _ := g.findBlockDef("unless")
require.True(t, elseBlock.CanHaveParent(ifBlock))
require.False(t, elseBlock.CanHaveParent(unlessBlock))
require.Equal(t, []string{"case", "if"}, elseBlock.ParentTags())
}
2 changes: 1 addition & 1 deletion render/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (c Config) compileNode(n parser.ASTNode) (Node, parser.Error) {
}
return &TagNode{n.Token, f}, nil
}
return nil, parser.Errorf(n, "unknown tag %q", n.Name)
return nil, parser.Errorf(n, "undefined tag %q", n.Name)
case *parser.ASTText:
return &TextNode{n.Token}, nil
case *parser.ASTObject:
Expand Down
12 changes: 9 additions & 3 deletions render/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@ import (

func addCompilerTestTags(s Config) {
s.AddBlock("block").Compiler(func(c BlockNode) (func(io.Writer, Context) error, error) {
return func(io.Writer, Context) error {
return nil
}, nil
})
s.AddBlock("error_block").Compiler(func(c BlockNode) (func(io.Writer, Context) error, error) {
return nil, fmt.Errorf("block compiler error")
})
}

var compilerErrorTests = []struct{ in, expected string }{
{`{% unknown_tag %}`, "unknown tag"},
{`{% block %}{% endblock %}`, "block compiler error"},
{`{% undefined_tag %}`, "undefined tag"},
{`{% error_block %}{% enderror_block %}`, "block compiler error"},
{`{% block %}{% undefined_tag %}{% endblock %}`, "undefined tag"},
// {`{% tag %}`, "tag compiler error"},
// {`{%for syntax error%}{%endfor%}`, "syntax error"},
}

func TestCompileErrors(t *testing.T) {
func TestCompile_errors(t *testing.T) {
settings := NewConfig()
addCompilerTestTags(settings)
for i, test := range compilerErrorTests {
Expand Down
12 changes: 0 additions & 12 deletions render/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package render

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"strings"
Expand Down Expand Up @@ -74,17 +73,6 @@ func (c rendererContext) Evaluate(expr expressions.Expression) (out interface{},

// EvaluateString evaluates an expression within the template context.
func (c rendererContext) EvaluateString(source string) (out interface{}, err error) {
defer func() {
if r := recover(); r != nil {
switch e := r.(type) {
case expressions.InterpreterError:
err = e
default:
// fmt.Println(string(debug.Stack()))
panic(fmt.Errorf("%s during evaluation of %s", e, source))
}
}
}()
return expressions.EvaluateString(source, expressions.NewContext(c.ctx.bindings, c.ctx.config.Config.Config))
}

Expand Down
8 changes: 4 additions & 4 deletions render/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import (
"github.com/stretchr/testify/require"
)

func addRenderTestTags(s Config) {
s.AddTag("y", func(string) (func(io.Writer, Context) error, error) {
func addRenderTestTags(cfg Config) {
cfg.AddTag("y", func(string) (func(io.Writer, Context) error, error) {
return func(w io.Writer, _ Context) error {
_, err := io.WriteString(w, "y")
return err
}, nil
})
s.AddTag("null", func(string) (func(io.Writer, Context) error, error) {
cfg.AddTag("null", func(string) (func(io.Writer, Context) error, error) {
return func(io.Writer, Context) error { return nil }, nil
})
s.AddBlock("errblock").Compiler(func(c BlockNode) (func(io.Writer, Context) error, error) {
cfg.AddBlock("errblock").Compiler(func(c BlockNode) (func(io.Writer, Context) error, error) {
return func(w io.Writer, c Context) error {
return fmt.Errorf("errblock error")
}, nil
Expand Down
7 changes: 5 additions & 2 deletions tags/iteration_tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var iterationTests = []struct{ in, expected string }{
{`{% for a in array reversed limit: 1 %}{{ a }}.{% endfor %}`, "third."},
{`{% for a in array limit: 0 %}{{ a }}.{% endfor %}`, ""},
{`{% for a in array offset: 3 %}{{ a }}.{% endfor %}`, ""},
{`{% for a in array offset: 10 %}{{ a }}.{% endfor %}`, ""},
// TODO investigate how these combine; does it depend on the order?
// {`{% for a in array reversed offset:1 %}{{ a }}.{% endfor %}`, "second.first."},
// {`{% for a in array limit:1 offset:1 %}{{ a }}.{% endfor %}`, "second."},
Expand Down Expand Up @@ -100,6 +101,8 @@ var iterationErrorTests = []struct{ in, expected string }{
{`{% break %}`, "break outside a loop"},
{`{% continue %}`, "continue outside a loop"},
{`{% cycle 'a', 'b' %}`, "cycle must be within a forloop"},
{`{% for a in array | undefined_filter %}{% endfor %}`, "undefined filter"},
{`{% for a in array %}{{ a | undefined_filter }}{% endfor %}`, "undefined filter"},
}

var iterationTestBindings = map[string]interface{}{
Expand Down Expand Up @@ -131,7 +134,7 @@ func TestIterationTags(t *testing.T) {
}
}

func TestLoopTag_errors(t *testing.T) {
func TestIterationTags_errors(t *testing.T) {
config := render.NewConfig()
AddStandardTags(config)

Expand All @@ -144,7 +147,7 @@ func TestLoopTag_errors(t *testing.T) {
}

for i, test := range iterationErrorTests {
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
t.Run(fmt.Sprintf("%02d", i+1+len(iterationSyntaxErrorTests)), func(t *testing.T) {
root, err := config.Compile(test.in, parser.SourceLoc{})
require.NoErrorf(t, err, test.in)
err = render.Render(root, ioutil.Discard, iterationTestBindings, config)
Expand Down
8 changes: 4 additions & 4 deletions tags/standard_tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import (
)

var parseErrorTests = []struct{ in, expected string }{
{"{% unknown_tag %}", "unknown tag"},
{"{% undefined_tag %}", "undefined tag"},
{"{% assign v x y z %}", "syntax error"},
{"{% if syntax error %}", `unterminated "if" block`},
// TODO once expression parsing is moved to template parse stage
// {"{% if syntax error %}{% endif %}", "syntax error"},
// {"{% for a in ar unknown %}{{ a }} {% endfor %}", "TODO"},
// {"{% for a in ar undefined %}{{ a }} {% endfor %}", "TODO"},
}

var tagTests = []struct{ in, expected string }{
Expand All @@ -27,10 +27,10 @@ var tagTests = []struct{ in, expected string }{
{`{% capture x %}captured{% endcapture %}{{ x }}`, "captured"},

// TODO research whether Liquid requires matching interior tags
{`{% comment %}{{ a }}{% unknown %}{% endcomment %}`, ""},
{`{% comment %}{{ a }}{% undefined_tag %}{% endcomment %}`, ""},

// TODO research whether Liquid requires matching interior tags
{`pre{% raw %}{{ a }}{% unknown %}{% endraw %}post`, "pre{{ a }}{% unknown %}post"},
{`pre{% raw %}{{ a }}{% undefined_tag %}{% endraw %}post`, "pre{{ a }}{% undefined_tag %}post"},
{`pre{% raw %}{% if false %}anyway-{% endraw %}post`, "pre{% if false %}anyway-post"},
}

Expand Down

0 comments on commit 413b328

Please sign in to comment.