mirror of
https://github.com/danog/liquid.git
synced 2024-11-26 21:14:45 +01:00
Coverage
This commit is contained in:
parent
1c94b61bcc
commit
a2a4a1a5ec
@ -35,15 +35,17 @@ func conversionError(modifier string, value interface{}, typ reflect.Type) error
|
||||
func Convert(value interface{}, typ reflect.Type) (interface{}, error) { // nolint: gocyclo
|
||||
value = ToLiquid(value)
|
||||
r := reflect.ValueOf(value)
|
||||
switch {
|
||||
case typ.Kind() != reflect.String && value != nil && r.Type().ConvertibleTo(typ):
|
||||
// convert int.Convert(string) yields "\x01" not "1"
|
||||
// int.Convert(string) returns "\x01" not "1", so guard against that in the following test
|
||||
if typ.Kind() != reflect.String && value != nil && r.Type().ConvertibleTo(typ) {
|
||||
return r.Convert(typ).Interface(), nil
|
||||
case typ == timeType && r.Kind() == reflect.String:
|
||||
return ParseDate(value.(string))
|
||||
// case reflect.PtrTo(r.Type()) == typ:
|
||||
// return &value, nil
|
||||
}
|
||||
if typ == timeType && r.Kind() == reflect.String {
|
||||
return ParseDate(value.(string))
|
||||
}
|
||||
// currently unused:
|
||||
// case reflect.PtrTo(r.Type()) == typ:
|
||||
// return &value, nil
|
||||
// }
|
||||
switch typ.Kind() {
|
||||
case reflect.Bool:
|
||||
return !(value == nil || value == false), nil
|
||||
@ -59,8 +61,7 @@ func Convert(value interface{}, typ reflect.Type) (interface{}, error) { // noli
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch value := value.(type) {
|
||||
case int:
|
||||
return float64(value), nil
|
||||
// case int is handled by r.Convert(type) above
|
||||
case string:
|
||||
return strconv.ParseFloat(value, 64)
|
||||
}
|
||||
|
@ -43,6 +43,13 @@ var convertTests = []struct {
|
||||
// {"March 14, 2016", time.Now(), timeMustParse("2016-03-14T00:00:00Z")},
|
||||
{redConvertible{}, "", "red"},
|
||||
}
|
||||
var convertErrorTests = []struct {
|
||||
value, proto, expected interface{}
|
||||
}{
|
||||
{map[string]bool{"k": true}, map[int]bool{}, "map key"},
|
||||
{map[string]string{"k": "v"}, map[string]int{}, "map value"},
|
||||
{map[interface{}]interface{}{"k": "v"}, map[string]int{}, "map value"},
|
||||
}
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
for i, test := range convertTests {
|
||||
@ -55,6 +62,19 @@ func TestConvert(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvert_errors(t *testing.T) {
|
||||
for i, test := range convertErrorTests {
|
||||
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
|
||||
typ := reflect.TypeOf(test.proto)
|
||||
name := fmt.Sprintf("Convert %#v -> %v", test.value, typ)
|
||||
_, err := Convert(test.value, typ)
|
||||
require.Errorf(t, err, name)
|
||||
require.Containsf(t, err.Error(), test.expected, name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvert_map(t *testing.T) {
|
||||
typ := reflect.TypeOf(map[string]string{})
|
||||
v, err := Convert(map[interface{}]interface{}{"key": "value"}, typ)
|
||||
@ -64,12 +84,6 @@ func TestConvert_map(t *testing.T) {
|
||||
require.Equal(t, "value", m["key"])
|
||||
}
|
||||
|
||||
func TestConvert_map_key_error(t *testing.T) {
|
||||
typ := reflect.TypeOf(map[string]int{})
|
||||
_, err := Convert(map[interface{}]interface{}{"key": "value"}, typ)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConvert_map_synonym(t *testing.T) {
|
||||
type VariableMap map[interface{}]interface{}
|
||||
typ := reflect.TypeOf(map[string]string{})
|
||||
|
@ -1,13 +1,13 @@
|
||||
%{
|
||||
package expressions
|
||||
import (
|
||||
"fmt"
|
||||
"fmt"
|
||||
"github.com/osteele/liquid/evaluator"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// This allows adding and removing references to fmt in the rules below,
|
||||
// without having to edit the import statement to avoid erorrs each time.
|
||||
// without having to comment and un-comment the import statement above.
|
||||
_ = fmt.Sprint("")
|
||||
}
|
||||
|
||||
|
@ -12,23 +12,27 @@ import (
|
||||
)
|
||||
|
||||
func addRenderTestTags(s Config) {
|
||||
s.AddBlock("err2").Compiler(func(c BlockNode) (func(io.Writer, Context) error, error) {
|
||||
s.AddBlock("errblock").Compiler(func(c BlockNode) (func(io.Writer, Context) error, error) {
|
||||
return func(w io.Writer, c Context) error {
|
||||
return fmt.Errorf("stage 2 error")
|
||||
return fmt.Errorf("errblock error")
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
var renderTests = []struct{ in, out string }{
|
||||
{`{{ nil }}`, ""},
|
||||
{`{{ true }}`, "true"},
|
||||
{`{{ false }}`, "false"},
|
||||
{`{{ 12 }}`, "12"},
|
||||
{`{{ 12.3 }}`, "12.3"},
|
||||
{`{{ "abc" }}`, "abc"},
|
||||
{`{{ x }}`, "123"},
|
||||
{`{{ page.title }}`, "Introduction"},
|
||||
{`{{ array[1] }}`, "second"},
|
||||
}
|
||||
|
||||
var renderErrorTests = []struct{ in, out string }{
|
||||
// {"{%if syntax error%}{%endif%}", "parse error"},
|
||||
{`{% err2 %}{% enderr2 %}`, "stage 2 error"},
|
||||
{`{% errblock %}{% enderrblock %}`, "errblock error"},
|
||||
}
|
||||
|
||||
var renderTestBindings = map[string]interface{}{
|
||||
|
@ -3,6 +3,8 @@ package tags
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/osteele/liquid/parser"
|
||||
@ -43,17 +45,53 @@ var cfTagTests = []struct{ in, expected string }{
|
||||
{`{% unless false %}true{% endunless %}`, "true"},
|
||||
}
|
||||
|
||||
var cfTagCompilationErrorTests = []struct{ in, expected string }{
|
||||
{`{% case syntax error %}{% when 1 %}{% endcase %}`, "syntax error"},
|
||||
}
|
||||
|
||||
var cfTagErrorTests = []struct{ in, expected string }{
|
||||
{`{% case 1 %}{% when 1 %}{% error %}{% endcase %}`, "tag render error"},
|
||||
}
|
||||
|
||||
func TestControlFlowTags(t *testing.T) {
|
||||
config := render.NewConfig()
|
||||
AddStandardTags(config)
|
||||
cfg := render.NewConfig()
|
||||
AddStandardTags(cfg)
|
||||
|
||||
for i, test := range cfTagTests {
|
||||
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
|
||||
ast, err := config.Compile(test.in, parser.SourceLoc{})
|
||||
root, err := cfg.Compile(test.in, parser.SourceLoc{})
|
||||
require.NoErrorf(t, err, test.in)
|
||||
buf := new(bytes.Buffer)
|
||||
err = render.Render(ast, buf, tagTestBindings, config)
|
||||
err = render.Render(root, buf, tagTestBindings, cfg)
|
||||
require.NoErrorf(t, err, test.in)
|
||||
require.Equalf(t, test.expected, buf.String(), test.in)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestControlFlowTags_errors(t *testing.T) {
|
||||
cfg := render.NewConfig()
|
||||
AddStandardTags(cfg)
|
||||
cfg.AddTag("error", func(string) (func(io.Writer, render.Context) error, error) {
|
||||
return func(io.Writer, render.Context) error {
|
||||
return fmt.Errorf("tag render error")
|
||||
}, nil
|
||||
})
|
||||
|
||||
for i, test := range cfTagCompilationErrorTests {
|
||||
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
|
||||
_, err := cfg.Compile(test.in, parser.SourceLoc{})
|
||||
require.Errorf(t, err, test.in)
|
||||
require.Contains(t, err.Error(), test.expected, test.in)
|
||||
})
|
||||
}
|
||||
for i, test := range cfTagErrorTests {
|
||||
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
|
||||
root, err := cfg.Compile(test.in, parser.SourceLoc{})
|
||||
require.NoErrorf(t, err, test.in)
|
||||
err = render.Render(root, ioutil.Discard, tagTestBindings, cfg)
|
||||
require.Errorf(t, err, test.in)
|
||||
require.Contains(t, err.Error(), test.expected, test.in)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package tags
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/osteele/liquid/parser"
|
||||
@ -10,7 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var loopTests = []struct{ in, expected string }{
|
||||
var iterationTests = []struct{ in, expected string }{
|
||||
{`{% for a in array %}{{ a }} {% endfor %}`, "first second third "},
|
||||
|
||||
// loop modifiers
|
||||
@ -69,12 +70,19 @@ var loopTests = []struct{ in, expected string }{
|
||||
{`{% for i in (3..5) %}{{i}}.{% endfor %}`, "3.4.5."},
|
||||
}
|
||||
|
||||
var loopErrorTests = []struct{ in, expected string }{
|
||||
{`{% break %}`, "break outside a loop"},
|
||||
{`{% continue %}`, "continue outside a loop"},
|
||||
var iterationSyntaxErrorTests = []struct{ in, expected string }{
|
||||
{`{% for a b c %}{% endfor %}`, "parse error"},
|
||||
{`{% for a in array offset %}{% endfor %}`, "undefined loop modifier"},
|
||||
{`{% cycle %}`, "parse error"},
|
||||
}
|
||||
|
||||
var loopTestBindings = map[string]interface{}{
|
||||
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"},
|
||||
}
|
||||
|
||||
var iterationTestBindings = map[string]interface{}{
|
||||
"array": []string{"first", "second", "third"},
|
||||
"hash": map[string]interface{}{"a": 1},
|
||||
}
|
||||
@ -82,12 +90,12 @@ var loopTestBindings = map[string]interface{}{
|
||||
func TestLoopTag(t *testing.T) {
|
||||
config := render.NewConfig()
|
||||
AddStandardTags(config)
|
||||
for i, test := range loopTests {
|
||||
for i, test := range iterationTests {
|
||||
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
|
||||
ast, err := config.Compile(test.in, parser.SourceLoc{})
|
||||
root, err := config.Compile(test.in, parser.SourceLoc{})
|
||||
require.NoErrorf(t, err, test.in)
|
||||
buf := new(bytes.Buffer)
|
||||
err = render.Render(ast, buf, loopTestBindings, config)
|
||||
err = render.Render(root, buf, iterationTestBindings, config)
|
||||
require.NoErrorf(t, err, test.in)
|
||||
require.Equalf(t, test.expected, buf.String(), test.in)
|
||||
})
|
||||
@ -97,12 +105,20 @@ func TestLoopTag(t *testing.T) {
|
||||
func TestLoopTag_errors(t *testing.T) {
|
||||
config := render.NewConfig()
|
||||
AddStandardTags(config)
|
||||
for i, test := range loopErrorTests {
|
||||
|
||||
for i, test := range iterationSyntaxErrorTests {
|
||||
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
|
||||
ast, err := config.Compile(test.in, parser.SourceLoc{})
|
||||
_, err := config.Compile(test.in, parser.SourceLoc{})
|
||||
require.Errorf(t, err, test.in)
|
||||
require.Containsf(t, err.Error(), test.expected, test.in)
|
||||
})
|
||||
}
|
||||
|
||||
for i, test := range iterationErrorTests {
|
||||
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
|
||||
root, err := config.Compile(test.in, parser.SourceLoc{})
|
||||
require.NoErrorf(t, err, test.in)
|
||||
buf := new(bytes.Buffer)
|
||||
err = render.Render(ast, buf, loopTestBindings, config)
|
||||
err = render.Render(root, ioutil.Discard, iterationTestBindings, config)
|
||||
require.Errorf(t, err, test.in)
|
||||
require.Containsf(t, err.Error(), test.expected, test.in)
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user