234 lines
4.5 KiB
Go
234 lines
4.5 KiB
Go
|
package configschema
|
||
|
|
||
|
import (
|
||
|
"testing"
|
||
|
|
||
|
"github.com/zclconf/go-cty/cty"
|
||
|
)
|
||
|
|
||
|
func TestCoerceValue(t *testing.T) {
|
||
|
tests := map[string]struct {
|
||
|
Schema *Block
|
||
|
Input cty.Value
|
||
|
WantValue cty.Value
|
||
|
WantErr string
|
||
|
}{
|
||
|
"empty schema and value": {
|
||
|
&Block{},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.EmptyObjectVal,
|
||
|
``,
|
||
|
},
|
||
|
"attribute present": {
|
||
|
&Block{
|
||
|
Attributes: map[string]*Attribute{
|
||
|
"foo": {
|
||
|
Type: cty.String,
|
||
|
Optional: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.True,
|
||
|
}),
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.StringVal("true"),
|
||
|
}),
|
||
|
``,
|
||
|
},
|
||
|
"single block present": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingSingle,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.EmptyObjectVal,
|
||
|
}),
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.EmptyObjectVal,
|
||
|
}),
|
||
|
``,
|
||
|
},
|
||
|
"single block wrong type": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingSingle,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.True,
|
||
|
}),
|
||
|
cty.DynamicVal,
|
||
|
`an object is required`,
|
||
|
},
|
||
|
"missing optional attribute": {
|
||
|
&Block{
|
||
|
Attributes: map[string]*Attribute{
|
||
|
"foo": {
|
||
|
Type: cty.String,
|
||
|
Optional: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.NullVal(cty.String),
|
||
|
}),
|
||
|
``,
|
||
|
},
|
||
|
"missing optional single block": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingSingle,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.NullVal(cty.EmptyObject),
|
||
|
}),
|
||
|
``,
|
||
|
},
|
||
|
"missing optional list block": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingList,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.ListValEmpty(cty.EmptyObject),
|
||
|
}),
|
||
|
``,
|
||
|
},
|
||
|
"missing optional set block": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingSet,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.SetValEmpty(cty.EmptyObject),
|
||
|
}),
|
||
|
``,
|
||
|
},
|
||
|
"missing optional map block": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingMap,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.MapValEmpty(cty.EmptyObject),
|
||
|
}),
|
||
|
``,
|
||
|
},
|
||
|
"missing required attribute": {
|
||
|
&Block{
|
||
|
Attributes: map[string]*Attribute{
|
||
|
"foo": {
|
||
|
Type: cty.String,
|
||
|
Required: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.DynamicVal,
|
||
|
`attribute "foo" is required`,
|
||
|
},
|
||
|
"missing required single block": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingSingle,
|
||
|
MinItems: 1,
|
||
|
MaxItems: 1,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.DynamicVal,
|
||
|
`attribute "foo" is required`,
|
||
|
},
|
||
|
"missing required list block": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingList,
|
||
|
MinItems: 1,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.DynamicVal,
|
||
|
`attribute "foo" is required`,
|
||
|
},
|
||
|
"missing required set block": {
|
||
|
&Block{
|
||
|
BlockTypes: map[string]*NestedBlock{
|
||
|
"foo": {
|
||
|
Block: Block{},
|
||
|
Nesting: NestingList,
|
||
|
MinItems: 1,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
cty.EmptyObjectVal,
|
||
|
cty.DynamicVal,
|
||
|
`attribute "foo" is required`,
|
||
|
},
|
||
|
"extraneous attribute": {
|
||
|
&Block{},
|
||
|
cty.ObjectVal(map[string]cty.Value{
|
||
|
"foo": cty.StringVal("bar"),
|
||
|
}),
|
||
|
cty.DynamicVal,
|
||
|
`unexpected attribute "foo"`,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for name, test := range tests {
|
||
|
t.Run(name, func(t *testing.T) {
|
||
|
gotValue, gotErrObj := test.Schema.CoerceValue(test.Input)
|
||
|
|
||
|
if gotErrObj == nil {
|
||
|
if test.WantErr != "" {
|
||
|
t.Fatalf("coersion succeeded; want error: %q", test.WantErr)
|
||
|
}
|
||
|
} else {
|
||
|
gotErr := gotErrObj.Error()
|
||
|
if gotErr != test.WantErr {
|
||
|
t.Fatalf("wrong error\ngot: %s\nwant: %s", gotErr, test.WantErr)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if !gotValue.RawEquals(test.WantValue) {
|
||
|
t.Errorf("wrong result\ninput: %#v\ngot: %#v\nwant: %#v", test.Input, gotValue, test.WantValue)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|