2017-09-11 23:00:31 +00:00
|
|
|
package hcldec
|
2017-07-17 23:54:24 +00:00
|
|
|
|
2018-05-22 22:06:42 +00:00
|
|
|
import (
|
2020-06-04 20:20:16 +00:00
|
|
|
"fmt"
|
2018-05-22 22:06:42 +00:00
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/apparentlymart/go-dump/dump"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
|
2019-09-09 23:08:19 +00:00
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
|
|
"github.com/hashicorp/hcl/v2/hclsyntax"
|
2018-05-22 22:06:42 +00:00
|
|
|
)
|
|
|
|
|
2017-07-17 23:54:24 +00:00
|
|
|
// Verify that all of our spec types implement the necessary interfaces
|
2018-01-22 02:08:43 +00:00
|
|
|
var _ Spec = ObjectSpec(nil)
|
|
|
|
var _ Spec = TupleSpec(nil)
|
|
|
|
var _ Spec = (*AttrSpec)(nil)
|
|
|
|
var _ Spec = (*LiteralSpec)(nil)
|
|
|
|
var _ Spec = (*ExprSpec)(nil)
|
|
|
|
var _ Spec = (*BlockSpec)(nil)
|
|
|
|
var _ Spec = (*BlockListSpec)(nil)
|
|
|
|
var _ Spec = (*BlockSetSpec)(nil)
|
|
|
|
var _ Spec = (*BlockMapSpec)(nil)
|
2018-08-09 23:53:16 +00:00
|
|
|
var _ Spec = (*BlockAttrsSpec)(nil)
|
2018-01-22 02:08:43 +00:00
|
|
|
var _ Spec = (*BlockLabelSpec)(nil)
|
|
|
|
var _ Spec = (*DefaultSpec)(nil)
|
2018-02-04 17:59:20 +00:00
|
|
|
var _ Spec = (*TransformExprSpec)(nil)
|
|
|
|
var _ Spec = (*TransformFuncSpec)(nil)
|
2020-06-04 20:20:16 +00:00
|
|
|
var _ Spec = (*ValidateSpec)(nil)
|
2018-01-22 02:08:43 +00:00
|
|
|
|
|
|
|
var _ attrSpec = (*AttrSpec)(nil)
|
2018-05-22 22:06:42 +00:00
|
|
|
var _ attrSpec = (*DefaultSpec)(nil)
|
2018-01-22 02:08:43 +00:00
|
|
|
|
|
|
|
var _ blockSpec = (*BlockSpec)(nil)
|
|
|
|
var _ blockSpec = (*BlockListSpec)(nil)
|
|
|
|
var _ blockSpec = (*BlockSetSpec)(nil)
|
|
|
|
var _ blockSpec = (*BlockMapSpec)(nil)
|
2018-08-09 23:53:16 +00:00
|
|
|
var _ blockSpec = (*BlockAttrsSpec)(nil)
|
2018-05-22 22:06:42 +00:00
|
|
|
var _ blockSpec = (*DefaultSpec)(nil)
|
|
|
|
|
|
|
|
var _ specNeedingVariables = (*AttrSpec)(nil)
|
|
|
|
var _ specNeedingVariables = (*BlockSpec)(nil)
|
|
|
|
var _ specNeedingVariables = (*BlockListSpec)(nil)
|
|
|
|
var _ specNeedingVariables = (*BlockSetSpec)(nil)
|
|
|
|
var _ specNeedingVariables = (*BlockMapSpec)(nil)
|
2018-08-09 23:53:16 +00:00
|
|
|
var _ specNeedingVariables = (*BlockAttrsSpec)(nil)
|
2018-05-22 22:06:42 +00:00
|
|
|
|
|
|
|
func TestDefaultSpec(t *testing.T) {
|
|
|
|
config := `
|
|
|
|
foo = fooval
|
|
|
|
bar = barval
|
|
|
|
`
|
|
|
|
f, diags := hclsyntax.ParseConfig([]byte(config), "", hcl.Pos{Line: 1, Column: 1})
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("primary set", func(t *testing.T) {
|
|
|
|
spec := &DefaultSpec{
|
|
|
|
Primary: &AttrSpec{
|
|
|
|
Name: "foo",
|
|
|
|
Type: cty.String,
|
|
|
|
},
|
|
|
|
Default: &AttrSpec{
|
|
|
|
Name: "bar",
|
|
|
|
Type: cty.String,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
gotVars := Variables(f.Body, spec)
|
|
|
|
wantVars := []hcl.Traversal{
|
|
|
|
{
|
|
|
|
hcl.TraverseRoot{
|
|
|
|
Name: "fooval",
|
|
|
|
SrcRange: hcl.Range{
|
|
|
|
Filename: "",
|
|
|
|
Start: hcl.Pos{Line: 2, Column: 7, Byte: 7},
|
|
|
|
End: hcl.Pos{Line: 2, Column: 13, Byte: 13},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
hcl.TraverseRoot{
|
|
|
|
Name: "barval",
|
|
|
|
SrcRange: hcl.Range{
|
|
|
|
Filename: "",
|
|
|
|
Start: hcl.Pos{Line: 3, Column: 7, Byte: 20},
|
|
|
|
End: hcl.Pos{Line: 3, Column: 13, Byte: 26},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(gotVars, wantVars) {
|
|
|
|
t.Errorf("wrong Variables result\ngot: %s\nwant: %s", dump.Value(gotVars), dump.Value(wantVars))
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := &hcl.EvalContext{
|
|
|
|
Variables: map[string]cty.Value{
|
|
|
|
"fooval": cty.StringVal("foo value"),
|
|
|
|
"barval": cty.StringVal("bar value"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
got, err := Decode(f.Body, spec, ctx)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
want := cty.StringVal("foo value")
|
|
|
|
if !got.RawEquals(want) {
|
|
|
|
t.Errorf("wrong Decode result\ngot: %#v\nwant: %#v", got, want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("primary not set", func(t *testing.T) {
|
|
|
|
spec := &DefaultSpec{
|
|
|
|
Primary: &AttrSpec{
|
|
|
|
Name: "foo",
|
|
|
|
Type: cty.String,
|
|
|
|
},
|
|
|
|
Default: &AttrSpec{
|
|
|
|
Name: "bar",
|
|
|
|
Type: cty.String,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := &hcl.EvalContext{
|
|
|
|
Variables: map[string]cty.Value{
|
|
|
|
"fooval": cty.NullVal(cty.String),
|
|
|
|
"barval": cty.StringVal("bar value"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
got, err := Decode(f.Body, spec, ctx)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
want := cty.StringVal("bar value")
|
|
|
|
if !got.RawEquals(want) {
|
|
|
|
t.Errorf("wrong Decode result\ngot: %#v\nwant: %#v", got, want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-06-04 20:20:16 +00:00
|
|
|
|
|
|
|
func TestValidateFuncSpec(t *testing.T) {
|
|
|
|
config := `
|
|
|
|
foo = "invalid"
|
|
|
|
`
|
|
|
|
f, diags := hclsyntax.ParseConfig([]byte(config), "", hcl.Pos{Line: 1, Column: 1})
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
expectRange := map[string]*hcl.Range{
|
|
|
|
"without_range": nil,
|
|
|
|
"with_range": &hcl.Range{
|
|
|
|
Filename: "foobar",
|
|
|
|
Start: hcl.Pos{Line: 99, Column: 99},
|
|
|
|
End: hcl.Pos{Line: 999, Column: 999},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name := range expectRange {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
spec := &ValidateSpec{
|
|
|
|
Wrapped: &AttrSpec{
|
|
|
|
Name: "foo",
|
|
|
|
Type: cty.String,
|
|
|
|
},
|
|
|
|
Func: func(value cty.Value) hcl.Diagnostics {
|
|
|
|
if value.AsString() != "invalid" {
|
|
|
|
return hcl.Diagnostics{
|
|
|
|
&hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
Summary: "incorrect value",
|
|
|
|
Detail: fmt.Sprintf("invalid value passed in: %s", value.GoString()),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return hcl.Diagnostics{
|
|
|
|
&hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagWarning,
|
|
|
|
Summary: "OK",
|
|
|
|
Detail: "validation called correctly",
|
|
|
|
Subject: expectRange[name],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, diags = Decode(f.Body, spec, nil)
|
|
|
|
if len(diags) != 1 ||
|
|
|
|
diags[0].Severity != hcl.DiagWarning ||
|
|
|
|
diags[0].Summary != "OK" ||
|
|
|
|
diags[0].Detail != "validation called correctly" {
|
|
|
|
t.Fatalf("unexpected diagnostics: %s", diags.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if expectRange[name] == nil && diags[0].Subject == nil {
|
|
|
|
t.Fatal("returned diagnostic subject missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
if expectRange[name] != nil && !reflect.DeepEqual(expectRange[name], diags[0].Subject) {
|
|
|
|
t.Fatalf("expected range %s, got range %s", expectRange[name], diags[0].Subject)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|