zcldec: flesh out and test the Variables function

It no longer produces diagnostics, since that's redundant with the
diagnostics that Decode itself will produce, and it wasn't going to be
complete anyway due to our use of partial decoding and our inability
to thread through nested specs in child blocks.
This commit is contained in:
Martin Atkins 2017-06-04 08:30:54 -07:00
parent a9f913f830
commit 1979cb4c56
3 changed files with 133 additions and 9 deletions

View File

@ -242,6 +242,25 @@ func (s *BlockSpec) blockHeaderSchemata() []zcl.BlockHeaderSchema {
}
}
// specNeedingVariables implementation
func (s *BlockSpec) variablesNeeded(content *zcl.BodyContent) []zcl.Traversal {
var childBlock *zcl.Block
for _, candidate := range content.Blocks {
if candidate.Type != s.TypeName {
continue
}
childBlock = candidate
break
}
if childBlock == nil {
return nil
}
return Variables(childBlock.Body, s.Nested)
}
func (s *BlockSpec) decode(content *zcl.BodyContent, block *zcl.Block, ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) {
var diags zcl.Diagnostics

View File

@ -11,18 +11,15 @@ import (
// This can be used to conditionally populate the variables in the EvalContext
// passed to Decode, for applications where a static scope is insufficient.
//
// If the given body is not compliant with the given schema, diagnostics are
// returned describing the problem, which could also serve as a pre-evaluation
// partial validation step.
func Variables(body zcl.Body, spec Spec) ([]zcl.Traversal, zcl.Diagnostics) {
// If the given body is not compliant with the given schema, the result may
// be incomplete, but that's assumed to be okay because the eventual call
// to Decode will produce error diagnostics anyway.
func Variables(body zcl.Body, spec Spec) []zcl.Traversal {
schema := ImpliedSchema(spec)
content, _, diags := body.PartialContent(schema)
content, _, _ := body.PartialContent(schema)
var vars []zcl.Traversal
if diags.HasErrors() {
return vars, diags
}
if vs, ok := spec.(specNeedingVariables); ok {
vars = append(vars, vs.variablesNeeded(content)...)
@ -33,5 +30,5 @@ func Variables(body zcl.Body, spec Spec) ([]zcl.Traversal, zcl.Diagnostics) {
}
})
return vars, diags
return vars
}

108
zcldec/variables_test.go Normal file
View File

@ -0,0 +1,108 @@
package zcldec
import (
"fmt"
"reflect"
"testing"
"github.com/zclconf/go-zcl/zcl"
"github.com/zclconf/go-zcl/zcl/zclsyntax"
)
func TestVariables(t *testing.T) {
tests := []struct {
config string
spec Spec
want []zcl.Traversal
}{
{
``,
&ObjectSpec{},
nil,
},
{
`a = foo`,
&ObjectSpec{},
nil, // "a" is not actually used, so "foo" is not required
},
{
`a = foo`,
&AttrSpec{
Name: "a",
},
[]zcl.Traversal{
{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 5, Byte: 4},
End: zcl.Pos{Line: 1, Column: 8, Byte: 7},
},
},
},
},
},
{
`a = foo`,
&ObjectSpec{
"a": &AttrSpec{
Name: "a",
},
},
[]zcl.Traversal{
{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 5, Byte: 4},
End: zcl.Pos{Line: 1, Column: 8, Byte: 7},
},
},
},
},
},
{
`
b {
a = foo
}`,
&BlockSpec{
TypeName: "b",
Nested: &AttrSpec{
Name: "a",
},
},
[]zcl.Traversal{
{
zcl.TraverseRoot{
Name: "foo",
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 3, Column: 7, Byte: 11},
End: zcl.Pos{Line: 3, Column: 10, Byte: 14},
},
},
},
},
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%02d-%s", i, test.config), func(t *testing.T) {
file, diags := zclsyntax.ParseConfig([]byte(test.config), "", zcl.Pos{Line: 1, Column: 1, Byte: 0})
if len(diags) != 0 {
t.Errorf("wrong number of diagnostics from ParseConfig %d; want %d", len(diags), 0)
for _, diag := range diags {
t.Logf(" - %s", diag.Error())
}
}
body := file.Body
got := Variables(body, test.spec)
if !reflect.DeepEqual(got, test.want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.want)
}
})
}
}