Files
opentf/internal/configs/configschema/empty_unknown_value_test.go
Christian Mesh 505f87900a Deprecated resource blocks attrs (#3973)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
Signed-off-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
Co-authored-by: Martin Atkins <mart@degeneration.co.uk>
Co-authored-by: Andrei Ciobanu <andreic9203@gmail.com>
Co-authored-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
2026-04-07 10:30:43 -04:00

309 lines
6.8 KiB
Go

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package configschema
import (
"fmt"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/zclconf/go-cty-debug/ctydebug"
"github.com/zclconf/go-cty/cty"
)
func TestBlockEmptyAndUnknownValue(t *testing.T) {
tests := []struct {
Schema *Block
Empty cty.Value
Unknown cty.Value
}{
{
&Block{},
cty.EmptyObjectVal,
cty.ObjectVal(nil),
},
{
&Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
cty.ObjectVal(map[string]cty.Value{
"str": cty.NullVal(cty.String),
}),
cty.ObjectVal(map[string]cty.Value{
"str": cty.UnknownVal(cty.String),
}),
},
{
&Block{
BlockTypes: map[string]*NestedBlock{
"single": {
Nesting: NestingSingle,
Block: Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"single": cty.NullVal(cty.Object(map[string]cty.Type{
"str": cty.String,
})),
}),
cty.ObjectVal(map[string]cty.Value{
"single": cty.UnknownVal(cty.Object(map[string]cty.Type{
"str": cty.String,
})),
}),
},
{
&Block{
BlockTypes: map[string]*NestedBlock{
"group": {
Nesting: NestingGroup,
Block: Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"group": cty.ObjectVal(map[string]cty.Value{
"str": cty.NullVal(cty.String),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"group": cty.UnknownVal(cty.Object(map[string]cty.Type{
"str": cty.String,
})),
}),
},
{
&Block{
BlockTypes: map[string]*NestedBlock{
"list": {
Nesting: NestingList,
Block: Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"list": cty.ListValEmpty(cty.Object(map[string]cty.Type{
"str": cty.String,
})),
}),
cty.ObjectVal(map[string]cty.Value{
"list": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
"str": cty.String,
}))),
}),
},
{
&Block{
BlockTypes: map[string]*NestedBlock{
"list_dynamic": {
Nesting: NestingList,
Block: Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.DynamicPseudoType, Required: true},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"list_dynamic": cty.EmptyTupleVal,
}),
cty.ObjectVal(map[string]cty.Value{
"list_dynamic": cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{
"str": cty.DynamicPseudoType,
}))),
}),
},
{
&Block{
BlockTypes: map[string]*NestedBlock{
"map": {
Nesting: NestingMap,
Block: Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{
"str": cty.String,
})),
}),
cty.ObjectVal(map[string]cty.Value{
"map": cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{
"str": cty.String,
}))),
}),
},
{
&Block{
BlockTypes: map[string]*NestedBlock{
"map_dynamic": {
Nesting: NestingMap,
Block: Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.DynamicPseudoType, Required: true},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"map_dynamic": cty.EmptyObjectVal,
}),
cty.ObjectVal(map[string]cty.Value{
"map_dynamic": cty.UnknownVal(cty.Map(cty.Object(map[string]cty.Type{
"str": cty.DynamicPseudoType,
}))),
}),
},
{
&Block{
BlockTypes: map[string]*NestedBlock{
"set": {
Nesting: NestingSet,
Block: Block{
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{
"str": cty.String,
})),
}),
cty.ObjectVal(map[string]cty.Value{
"set": cty.UnknownVal(cty.Set(cty.Object(map[string]cty.Type{
"str": cty.String,
}))),
}),
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("empty: %#v", test.Schema), func(t *testing.T) {
got := test.Schema.EmptyValue()
if !test.Empty.RawEquals(got) {
t.Errorf("wrong result\nschema: %s\ngot: %s\nwant: %s", spew.Sdump(test.Schema), ctydebug.ValueString(got), ctydebug.ValueString(test.Empty))
}
})
t.Run(fmt.Sprintf("unknown: %#v", test.Schema), func(t *testing.T) {
got := test.Schema.UnknownValue()
if !test.Unknown.RawEquals(got) {
t.Errorf("wrong result\nschema: %s\ngot: %s\nwant: %s", spew.Sdump(test.Schema), ctydebug.ValueString(got), ctydebug.ValueString(test.Unknown))
}
})
}
}
// Attribute EmptyValue() is well covered by the Block tests above; these tests
// focus on the behavior with NestedType field inside an Attribute
func TestAttributeEmptyValue(t *testing.T) {
tests := []struct {
Schema *Attribute
Want cty.Value
}{
{
&Attribute{},
cty.NilVal,
},
{
&Attribute{
Type: cty.String,
},
cty.NullVal(cty.String),
},
{
&Attribute{
NestedType: &Object{
Nesting: NestingSingle,
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
cty.NullVal(cty.Object(map[string]cty.Type{
"str": cty.String,
})),
},
{
&Attribute{
NestedType: &Object{
Nesting: NestingList,
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
cty.NullVal(cty.List(
cty.Object(map[string]cty.Type{
"str": cty.String,
}),
)),
},
{
&Attribute{
NestedType: &Object{
Nesting: NestingMap,
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
cty.NullVal(cty.Map(
cty.Object(map[string]cty.Type{
"str": cty.String,
}),
)),
},
{
&Attribute{
NestedType: &Object{
Nesting: NestingSet,
Attributes: map[string]*Attribute{
"str": {Type: cty.String, Required: true},
},
},
},
cty.NullVal(cty.Set(
cty.Object(map[string]cty.Type{
"str": cty.String,
}),
)),
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%#v", test.Schema), func(t *testing.T) {
got := test.Schema.EmptyValue()
if !test.Want.RawEquals(got) {
t.Errorf("wrong result\nschema: %s\ngot: %s\nwant: %s", spew.Sdump(test.Schema), ctydebug.ValueString(got), ctydebug.ValueString(test.Want))
}
})
}
}