e24fecb79d
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.
228 lines
4.8 KiB
Go
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))
|
|
}
|
|
})
|
|
}
|
|
}
|