opentofu/internal/configs/hcl2shim/values_test.go
Martin Atkins 31349a9c3a Move configs/ to internal/configs/
This is part of a general effort to move all of Terraform's non-library
package surface under internal in order to reinforce that these are for
internal use within Terraform only.

If you were previously importing packages under this prefix into an
external codebase, you could pin to an earlier release tag as an interim
solution until you've make a plan to achieve the same functionality some
other way.
2021-05-17 14:09:07 -07:00

416 lines
9.5 KiB
Go

package hcl2shim
import (
"fmt"
"reflect"
"testing"
"github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/zclconf/go-cty/cty"
)
func TestConfigValueFromHCL2Block(t *testing.T) {
tests := []struct {
Input cty.Value
Schema *configschema.Block
Want map[string]interface{}
}{
{
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("Ermintrude"),
"age": cty.NumberIntVal(19),
"address": cty.ObjectVal(map[string]cty.Value{
"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
"city": cty.StringVal("Fridgewater"),
"state": cty.StringVal("MA"),
"zip": cty.StringVal("91037"),
}),
}),
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"name": {Type: cty.String, Optional: true},
"age": {Type: cty.Number, Optional: true},
},
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingSingle,
Block: configschema.Block{
Attributes: map[string]*configschema.Attribute{
"street": {Type: cty.List(cty.String), Optional: true},
"city": {Type: cty.String, Optional: true},
"state": {Type: cty.String, Optional: true},
"zip": {Type: cty.String, Optional: true},
},
},
},
},
},
map[string]interface{}{
"name": "Ermintrude",
"age": int(19),
"address": map[string]interface{}{
"street": []interface{}{"421 Shoreham Loop"},
"city": "Fridgewater",
"state": "MA",
"zip": "91037",
},
},
},
{
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("Ermintrude"),
"age": cty.NumberIntVal(19),
"address": cty.NullVal(cty.Object(map[string]cty.Type{
"street": cty.List(cty.String),
"city": cty.String,
"state": cty.String,
"zip": cty.String,
})),
}),
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"name": {Type: cty.String, Optional: true},
"age": {Type: cty.Number, Optional: true},
},
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingSingle,
Block: configschema.Block{
Attributes: map[string]*configschema.Attribute{
"street": {Type: cty.List(cty.String), Optional: true},
"city": {Type: cty.String, Optional: true},
"state": {Type: cty.String, Optional: true},
"zip": {Type: cty.String, Optional: true},
},
},
},
},
},
map[string]interface{}{
"name": "Ermintrude",
"age": int(19),
},
},
{
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("Ermintrude"),
"age": cty.NumberIntVal(19),
"address": cty.ObjectVal(map[string]cty.Value{
"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
"city": cty.StringVal("Fridgewater"),
"state": cty.StringVal("MA"),
"zip": cty.NullVal(cty.String), // should be omitted altogether in result
}),
}),
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"name": {Type: cty.String, Optional: true},
"age": {Type: cty.Number, Optional: true},
},
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingSingle,
Block: configschema.Block{
Attributes: map[string]*configschema.Attribute{
"street": {Type: cty.List(cty.String), Optional: true},
"city": {Type: cty.String, Optional: true},
"state": {Type: cty.String, Optional: true},
"zip": {Type: cty.String, Optional: true},
},
},
},
},
},
map[string]interface{}{
"name": "Ermintrude",
"age": int(19),
"address": map[string]interface{}{
"street": []interface{}{"421 Shoreham Loop"},
"city": "Fridgewater",
"state": "MA",
},
},
},
{
cty.ObjectVal(map[string]cty.Value{
"address": cty.ListVal([]cty.Value{cty.EmptyObjectVal}),
}),
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingList,
Block: configschema.Block{},
},
},
},
map[string]interface{}{
"address": []interface{}{
map[string]interface{}{},
},
},
},
{
cty.ObjectVal(map[string]cty.Value{
"address": cty.ListValEmpty(cty.EmptyObject), // should be omitted altogether in result
}),
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingList,
Block: configschema.Block{},
},
},
},
map[string]interface{}{},
},
{
cty.ObjectVal(map[string]cty.Value{
"address": cty.SetVal([]cty.Value{cty.EmptyObjectVal}),
}),
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingSet,
Block: configschema.Block{},
},
},
},
map[string]interface{}{
"address": []interface{}{
map[string]interface{}{},
},
},
},
{
cty.ObjectVal(map[string]cty.Value{
"address": cty.SetValEmpty(cty.EmptyObject),
}),
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingSet,
Block: configschema.Block{},
},
},
},
map[string]interface{}{},
},
{
cty.ObjectVal(map[string]cty.Value{
"address": cty.MapVal(map[string]cty.Value{"foo": cty.EmptyObjectVal}),
}),
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingMap,
Block: configschema.Block{},
},
},
},
map[string]interface{}{
"address": map[string]interface{}{
"foo": map[string]interface{}{},
},
},
},
{
cty.ObjectVal(map[string]cty.Value{
"address": cty.MapValEmpty(cty.EmptyObject),
}),
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"address": {
Nesting: configschema.NestingMap,
Block: configschema.Block{},
},
},
},
map[string]interface{}{},
},
{
cty.NullVal(cty.EmptyObject),
&configschema.Block{},
nil,
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
got := ConfigValueFromHCL2Block(test.Input, test.Schema)
if !reflect.DeepEqual(got, test.Want) {
t.Errorf("wrong result\ninput: %#v\ngot: %#v\nwant: %#v", test.Input, got, test.Want)
}
})
}
}
func TestConfigValueFromHCL2(t *testing.T) {
tests := []struct {
Input cty.Value
Want interface{}
}{
{
cty.True,
true,
},
{
cty.False,
false,
},
{
cty.NumberIntVal(12),
int(12),
},
{
cty.NumberFloatVal(12.5),
float64(12.5),
},
{
cty.StringVal("hello world"),
"hello world",
},
{
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("Ermintrude"),
"age": cty.NumberIntVal(19),
"address": cty.ObjectVal(map[string]cty.Value{
"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
"city": cty.StringVal("Fridgewater"),
"state": cty.StringVal("MA"),
"zip": cty.StringVal("91037"),
}),
}),
map[string]interface{}{
"name": "Ermintrude",
"age": int(19),
"address": map[string]interface{}{
"street": []interface{}{"421 Shoreham Loop"},
"city": "Fridgewater",
"state": "MA",
"zip": "91037",
},
},
},
{
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
"bar": cty.StringVal("baz"),
}),
map[string]interface{}{
"foo": "bar",
"bar": "baz",
},
},
{
cty.TupleVal([]cty.Value{
cty.StringVal("foo"),
cty.True,
}),
[]interface{}{
"foo",
true,
},
},
{
cty.NullVal(cty.String),
nil,
},
{
cty.UnknownVal(cty.String),
UnknownVariableValue,
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
got := ConfigValueFromHCL2(test.Input)
if !reflect.DeepEqual(got, test.Want) {
t.Errorf("wrong result\ninput: %#v\ngot: %#v\nwant: %#v", test.Input, got, test.Want)
}
})
}
}
func TestHCL2ValueFromConfigValue(t *testing.T) {
tests := []struct {
Input interface{}
Want cty.Value
}{
{
nil,
cty.NullVal(cty.DynamicPseudoType),
},
{
UnknownVariableValue,
cty.DynamicVal,
},
{
true,
cty.True,
},
{
false,
cty.False,
},
{
int(12),
cty.NumberIntVal(12),
},
{
int(0),
cty.Zero,
},
{
float64(12.5),
cty.NumberFloatVal(12.5),
},
{
"hello world",
cty.StringVal("hello world"),
},
{
"O\u0308", // decomposed letter + diacritic
cty.StringVal("\u00D6"), // NFC-normalized on entry into cty
},
{
[]interface{}{},
cty.EmptyTupleVal,
},
{
[]interface{}(nil),
cty.EmptyTupleVal,
},
{
[]interface{}{"hello", "world"},
cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}),
},
{
map[string]interface{}{},
cty.EmptyObjectVal,
},
{
map[string]interface{}(nil),
cty.EmptyObjectVal,
},
{
map[string]interface{}{
"foo": "bar",
"bar": "baz",
},
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
"bar": cty.StringVal("baz"),
}),
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
got := HCL2ValueFromConfigValue(test.Input)
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ninput: %#v\ngot: %#v\nwant: %#v", test.Input, got, test.Want)
}
})
}
}