hcl/zcl/zclsyntax/parse_traversal_test.go
Martin Atkins e24fecb79d zclsyntax: ParseTraversalAbs function
This uses a subset of the expression syntax to allow representations of
traversals. The use-case for this is in applications that need to support
references to objects using familiar syntax without actually evaluating
those objects or dealing with the complexity of arbitrary expression
syntax.
2017-06-22 08:00:24 -07:00

228 lines
4.8 KiB
Go

package zclsyntax
import (
"testing"
"reflect"
"github.com/davecgh/go-spew/spew"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-zcl/zcl"
)
func TestParseTraversalAbs(t *testing.T) {
tests := []struct {
src string
want zcl.Traversal
diagCount int
}{
{
"",
nil,
1, // variable name required
},
{
"foo",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
},
0,
},
{
"foo.bar.baz",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
zcl.TraverseAttr{
Name: "bar",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 4, Byte: 3},
End: zcl.Pos{Line: 1, Column: 8, Byte: 7},
},
},
zcl.TraverseAttr{
Name: "baz",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 8, Byte: 7},
End: zcl.Pos{Line: 1, Column: 12, Byte: 11},
},
},
},
0,
},
{
"foo[1]",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
zcl.TraverseIndex{
Key: cty.NumberIntVal(1),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 4, Byte: 3},
End: zcl.Pos{Line: 1, Column: 7, Byte: 6},
},
},
},
0,
},
{
"foo[1][2]",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
zcl.TraverseIndex{
Key: cty.NumberIntVal(1),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 4, Byte: 3},
End: zcl.Pos{Line: 1, Column: 7, Byte: 6},
},
},
zcl.TraverseIndex{
Key: cty.NumberIntVal(2),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 7, Byte: 6},
End: zcl.Pos{Line: 1, Column: 10, Byte: 9},
},
},
},
0,
},
{
"foo[1].bar",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
zcl.TraverseIndex{
Key: cty.NumberIntVal(1),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 4, Byte: 3},
End: zcl.Pos{Line: 1, Column: 7, Byte: 6},
},
},
zcl.TraverseAttr{
Name: "bar",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 7, Byte: 6},
End: zcl.Pos{Line: 1, Column: 11, Byte: 10},
},
},
},
0,
},
{
"foo.",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
},
1, // attribute name required
},
{
"foo[",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
},
1, // index required
},
{
"foo[index]",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
},
1, // index must be literal
},
{
"foo[0",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
zcl.TraverseIndex{
Key: cty.NumberIntVal(0),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 4, Byte: 3},
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
},
},
},
1, // missing close bracket
},
{
"foo 0",
zcl.Traversal{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
},
1, // extra junk after traversal
},
}
for _, test := range tests {
t.Run(test.src, func(t *testing.T) {
got, diags := ParseTraversalAbs([]byte(test.src), "", zcl.Pos{Line: 1, Column: 1})
if len(diags) != test.diagCount {
for _, diag := range diags {
t.Logf(" - %s", diag.Error())
}
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.diagCount)
}
if !reflect.DeepEqual(got, test.want) {
t.Errorf("wrong result\nsrc: %s\ngot: %s\nwant: %s", test.src, spew.Sdump(got), spew.Sdump(test.want))
}
})
}
}