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) } }) } }