Files
expr/parser_test.go
T
2018-07-14 18:52:52 +03:00

182 lines
3.4 KiB
Go

package expr
import (
"fmt"
"reflect"
"strings"
"testing"
)
type parseTest struct {
input string
expected Node
}
var parseTests = []parseTest{
{
"a",
nameNode{"a"},
},
{
`"a"`,
textNode{"a"},
},
{
"3",
numberNode{3},
},
{
"true",
boolNode{true},
},
{
"false",
boolNode{false},
},
{
"nil",
nilNode{},
},
{
"-3",
unaryNode{"-", numberNode{3}},
},
{
"1 - 2",
binaryNode{"-", numberNode{1}, numberNode{2}},
},
{
"(1 - 2) * 3",
binaryNode{"*", binaryNode{"-", numberNode{1}, numberNode{2}}, numberNode{3}},
},
{
"2**4-1",
binaryNode{"-", binaryNode{"**", numberNode{2}, numberNode{4}}, numberNode{1}},
},
{
"foo(bar())",
functionNode{"foo", []Node{functionNode{"bar", []Node{}}}},
},
{
"foo.bar",
propertyNode{nameNode{"foo"}, identifierNode{"bar"}},
},
{
"foo.not",
propertyNode{nameNode{"foo"}, identifierNode{"not"}},
},
{
"foo.bar()",
methodNode{nameNode{"foo"}, identifierNode{"bar"}, []Node{}},
},
{
"foo.not()",
methodNode{nameNode{"foo"}, identifierNode{"not"}, []Node{}},
},
{
`foo.bar("arg1", 2, true)`,
methodNode{nameNode{"foo"}, identifierNode{"bar"}, []Node{textNode{"arg1"}, numberNode{2}, boolNode{true}}},
},
{
"foo[3]",
propertyNode{nameNode{"foo"}, numberNode{3}},
},
{
"true ? true : false",
conditionalNode{boolNode{true}, boolNode{true}, boolNode{false}},
},
{
"a ?: b",
conditionalNode{nameNode{"a"}, nameNode{"a"}, nameNode{"b"}},
},
{
`"foo" matches "/foo/"`,
binaryNode{"matches", textNode{"foo"}, textNode{"/foo/"}},
},
{
"foo.bar().foo().baz[33]",
propertyNode{propertyNode{methodNode{methodNode{nameNode{"foo"}, identifierNode{"bar"}, []Node{}}, identifierNode{"foo"}, []Node{}}, identifierNode{"baz"}}, numberNode{33}},
},
{
"+0 != -0",
binaryNode{"!=", unaryNode{"+", numberNode{0}}, unaryNode{"-", numberNode{0}}},
},
{
"[a, b, c]",
arrayNode{[]Node{nameNode{"a"}, nameNode{"b"}, nameNode{"c"}}},
},
{
"{foo:1, bar:2}",
mapNode{[]pairNode{{identifierNode{"foo"}, numberNode{1}}, {identifierNode{"bar"}, numberNode{2}}}},
},
{
`{"foo":1, (1+2):2}`,
mapNode{[]pairNode{{identifierNode{"foo"}, numberNode{1}}, {binaryNode{"+", numberNode{1}, numberNode{2}}, numberNode{2}}}},
},
{
"[1].foo",
propertyNode{arrayNode{[]Node{numberNode{1}}}, identifierNode{"foo"}},
},
{
"{foo:1}.bar",
propertyNode{mapNode{[]pairNode{{identifierNode{"foo"}, numberNode{1}}}}, identifierNode{"bar"}},
},
}
type parseErrorTest struct {
input string
err string
}
var parseErrorTests = []parseErrorTest{
{
"foo.",
"unexpected end of expression",
},
{
"a+",
"unexpected token EOF",
},
{
"a ? (1+2) c",
"unexpected token name(c)",
},
{
"[a b]",
"array items must be separated by a comma",
},
{
"foo.bar(a b)",
"arguments must be separated by a comma",
},
{
"{-}",
"a map key must be a",
},
}
func TestParse(t *testing.T) {
for _, test := range parseTests {
actual, err := Parse(test.input)
if err != nil {
t.Errorf("%s:\n%v", test.input, err)
continue
}
if !reflect.DeepEqual(actual, test.expected) {
t.Errorf("%s:\ngot\n\t%#v\nexpected\n\t%#v", test.input, actual, test.expected)
}
}
}
func TestParseError(t *testing.T) {
for _, test := range parseErrorTests {
_, err := Parse(test.input)
if err == nil {
err = fmt.Errorf("<nil>")
}
if !strings.HasPrefix(err.Error(), test.err) {
t.Errorf("%s:\ngot\n\t%+v\nexpected\n\t%v", test.input, err.Error(), test.err)
}
}
}