diff --git a/action/schema/unlinked_schema.go b/action/schema/unlinked_schema.go index 71af1a4f1..34da622e5 100644 --- a/action/schema/unlinked_schema.go +++ b/action/schema/unlinked_schema.go @@ -6,11 +6,12 @@ package schema import ( "context" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var _ SchemaType = UnlinkedSchema{} @@ -60,6 +61,10 @@ type UnlinkedSchema struct { func (s UnlinkedSchema) isActionSchemaType() {} +func (s UnlinkedSchema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s UnlinkedSchema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { diff --git a/datasource/schema/schema.go b/datasource/schema/schema.go index 90d1096c6..4e7e17e1a 100644 --- a/datasource/schema/schema.go +++ b/datasource/schema/schema.go @@ -61,6 +61,10 @@ type Schema struct { DeprecationMessage string } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { diff --git a/ephemeral/schema/schema.go b/ephemeral/schema/schema.go index 3c92269fb..091c8ad69 100644 --- a/ephemeral/schema/schema.go +++ b/ephemeral/schema/schema.go @@ -61,6 +61,10 @@ type Schema struct { DeprecationMessage string } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { diff --git a/internal/fwschema/nested_block_object.go b/internal/fwschema/nested_block_object.go index bc93a0992..dcdc5c528 100644 --- a/internal/fwschema/nested_block_object.go +++ b/internal/fwschema/nested_block_object.go @@ -6,10 +6,11 @@ package fwschema import ( "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // NestedBlockObject represents the Object inside a Block. diff --git a/internal/fwschema/schema.go b/internal/fwschema/schema.go index cc51acd8e..4a6a9d1cc 100644 --- a/internal/fwschema/schema.go +++ b/internal/fwschema/schema.go @@ -73,6 +73,9 @@ type Schema interface { // AttributeTypeAtPath should return the framework type of the Attribute at // the given Terraform path or return an error. TypeAtTerraformPath(context.Context, *tftypes.AttributePath) (attr.Type, error) + + // EmptyValue should return an empty tftypes.Value of the schema's TerraformType + EmptyValue(context.Context) tftypes.Value } // SchemaApplyTerraform5AttributePathStep is a helper function to perform base @@ -195,6 +198,19 @@ func SchemaTypeAtPath(ctx context.Context, s Schema, p path.Path) (attr.Type, di return attrType, diags } +func EmptySchemaValue(ctx context.Context, s Schema) tftypes.Value { + vals := make(map[string]tftypes.Value) + for name, attr := range s.GetAttributes() { + attr.GetType() + vals[name] = tftypes.NewValue(attr.GetType().TerraformType(ctx), nil) + } + for name, block := range s.GetBlocks() { + vals[name] = tftypes.NewValue(block.Type().TerraformType(ctx), nil) + } + + return tftypes.NewValue(s.Type().TerraformType(ctx), vals) +} + // SchemaTypeAtTerraformPath is a helper function to perform base type handling // using the tftypes.AttributePathStepper interface. func SchemaTypeAtTerraformPath(ctx context.Context, s Schema, p *tftypes.AttributePath) (attr.Type, error) { diff --git a/internal/fwserver/schema_propose_new_plan.go b/internal/fwserver/schema_propose_new_plan.go new file mode 100644 index 000000000..ccdc34250 --- /dev/null +++ b/internal/fwserver/schema_propose_new_plan.go @@ -0,0 +1,1264 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package fwserver + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fromtftypes" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +type ProposeNewStateRequest struct { + PriorState tfsdk.State + Config tfsdk.Config +} + +type ProposeNewStateResponse struct { + ProposedNewState tfsdk.Plan + Diagnostics diag.Diagnostics +} + +func SchemaProposeNewState(ctx context.Context, s fwschema.Schema, req ProposeNewStateRequest, resp *ProposeNewStateResponse) { + if req.PriorState.Raw.IsNull() { + // Populate prior state with a top-level round of nulls from the schema + req.PriorState = tfsdk.State{ + Raw: s.EmptyValue(ctx), + Schema: s, + } + } + + proposedNewState, diags := proposedNew(ctx, s, tftypes.NewAttributePath(), req.PriorState.Raw, req.Config.Raw) + resp.Diagnostics.Append(diags...) + + resp.ProposedNewState = tfsdk.Plan{ + Raw: proposedNewState, + Schema: s, + } +} + +func proposedNew(ctx context.Context, s fwschema.Schema, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + + if config.IsNull() { + return config, diags + } + + if !config.IsKnown() { + return prior, diags + } + + if (!prior.Type().Is(tftypes.Object{})) || (!config.Type().Is(tftypes.Object{})) { + diags.Append(diag.NewErrorDiagnostic( + "Invalid Value Type", + "An unexpected error occurred while trying to create the proposed new state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", "proposedNew only supports object-typed values"), + )) + return tftypes.Value{}, diags + } + + newAttrs, newAttrDiags := proposedNewAttributes(ctx, s, s.GetAttributes(), path, prior, config) + diags.Append(newAttrDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + + for name, blockType := range s.GetBlocks() { + attrVal, err := prior.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Attribute Path", + "An unexpected error occurred while trying to retrieve a value from prior state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + priorVal := attrVal.(tftypes.Value) //nolint + + attrVal, err = config.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Attribute Path", + "An unexpected error occurred while trying to retrieve a value from config. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + configVal := attrVal.(tftypes.Value) //nolint + + nestedBlockDiags := diag.Diagnostics{} //nolint + newAttrs[name], nestedBlockDiags = proposeNewNestedBlock(ctx, s, blockType, path.WithAttributeName(name), priorVal, configVal) + diags.Append(nestedBlockDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + } + + err := tftypes.ValidateValue(s.Type().TerraformType(ctx), newAttrs) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Value Type", + "An unexpected error occurred while trying to create the proposed new state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + return tftypes.NewValue(s.Type().TerraformType(ctx), newAttrs), diags +} + +func proposedNewAttributes(ctx context.Context, s fwschema.Schema, attrs map[string]fwschema.Attribute, path *tftypes.AttributePath, priorObj, configObj tftypes.Value) (map[string]tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + + newAttrs := make(map[string]tftypes.Value, len(attrs)) + + for name, attr := range attrs { + attrPath := path.WithAttributeName(name) + + var priorVal tftypes.Value + switch { + case priorObj.IsNull(): + priorObjType := priorObj.Type().(tftypes.Object) //nolint + + err := tftypes.ValidateValue(priorObjType.AttributeTypes[name], nil) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, attrPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Value Type", + "An unexpected error occurred while trying to validate a value from prior state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return nil, diags + } + + priorVal = tftypes.NewValue(priorObjType.AttributeTypes[name], nil) + case !priorObj.IsKnown(): + priorObjType := priorObj.Type().(tftypes.Object) //nolint + + err := tftypes.ValidateValue(priorObjType.AttributeTypes[name], tftypes.UnknownValue) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, attrPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Value Type", + "An unexpected error occurred while trying to validate a value from prior state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return nil, diags + } + + priorVal = tftypes.NewValue(priorObjType.AttributeTypes[name], tftypes.UnknownValue) + default: + attrVal, err := priorObj.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, attrPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Attribute Path", + "An unexpected error occurred while trying to retrieve a value from prior state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return nil, diags + } + priorVal = attrVal.(tftypes.Value) //nolint + + } + + var configVal tftypes.Value + switch { + case configObj.IsNull(): + configObjType := configObj.Type().(tftypes.Object) //nolint + + err := tftypes.ValidateValue(configObjType.AttributeTypes[name], nil) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, attrPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Value Type", + "An unexpected error occurred while trying to validate a value from config. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return nil, diags + } + + configVal = tftypes.NewValue(configObjType.AttributeTypes[name], nil) + case !configObj.IsKnown(): + configObjType := configObj.Type().(tftypes.Object) //nolint + + err := tftypes.ValidateValue(configObjType.AttributeTypes[name], tftypes.UnknownValue) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, attrPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Value Type", + "An unexpected error occurred while trying to validate a value from config. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return nil, diags + } + + configVal = tftypes.NewValue(configObjType.AttributeTypes[name], tftypes.UnknownValue) + default: + configIface, err := configObj.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, attrPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Attribute Path", + "An unexpected error occurred while trying to retrieve a value from config. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return nil, diags + } + configVal = configIface.(tftypes.Value) //nolint + + } + + var newVal tftypes.Value + if attr.IsComputed() && configVal.IsNull() { + newVal = priorVal + + notComputable, notComputableDiags := optionalValueNotComputable(ctx, s, attrPath, priorVal) + diags.Append(notComputableDiags...) + if diags.HasError() { + return map[string]tftypes.Value{}, diags + } + + if notComputable { + newVal = configVal + } + } else if nestedAttr, isNested := attr.(fwschema.NestedAttribute); isNested { + nestedAttrDiags := diag.Diagnostics{} //nolint + + newVal, nestedAttrDiags = proposeNewNestedAttribute(ctx, s, nestedAttr, attrPath, priorVal, configVal) + diags.Append(nestedAttrDiags...) + if diags.HasError() { + return nil, diags + } + } else { + newVal = configVal + } + + newAttrs[name] = newVal + } + + return newAttrs, diags +} + +func proposeNewNestedAttribute(ctx context.Context, s fwschema.Schema, attr fwschema.NestedAttribute, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + + // if the config isn't known at all, then we must use that value + if !config.IsKnown() { + return config, diags + } + + newVal := config + + switch attr.GetNestingMode() { + case fwschema.NestingModeSingle: + if config.IsNull() { + break + } + nestedDiags := diag.Diagnostics{} //nolint + newVal, nestedDiags = proposedNewNestedObjectAttributes(ctx, s, attr, path, prior, config) + diags.Append(nestedDiags...) + if nestedDiags.HasError() { + return tftypes.Value{}, diags + } + case fwschema.NestingModeList: + nestedDiags := diag.Diagnostics{} //nolint + newVal, nestedDiags = proposedNewListNested(ctx, s, attr, path, prior, config) + diags.Append(nestedDiags...) + if nestedDiags.HasError() { + return tftypes.Value{}, diags + } + case fwschema.NestingModeMap: + nestedDiags := diag.Diagnostics{} //nolint + newVal, nestedDiags = proposedNewMapNested(ctx, s, attr, path, prior, config) + diags.Append(nestedDiags...) + if nestedDiags.HasError() { + return tftypes.Value{}, diags + } + case fwschema.NestingModeSet: + nestedDiags := diag.Diagnostics{} //nolint + newVal, nestedDiags = proposedNewSetNested(ctx, s, attr, path, prior, config) + diags.Append(nestedDiags...) + if nestedDiags.HasError() { + return tftypes.Value{}, diags + } + default: + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Attribute Nesting Mode", + "An unexpected error occurred while trying to construct the proposed new state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", fmt.Sprintf("unsupported attribute nesting mode %d", attr.GetNestingMode())))) + + return tftypes.Value{}, diags + } + + return newVal, diags +} + +func proposedNewMapNested(ctx context.Context, s fwschema.Schema, attr fwschema.NestedAttribute, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + newVal := config + + configMap := make(map[string]tftypes.Value) + priorMap := make(map[string]tftypes.Value) + + configValLen := 0 + if !config.IsNull() { + err := config.As(&configMap) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Config Value", + "An unexpected error occurred while trying to convert the config value to a go map. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + configValLen = len(configMap) + } + + if !prior.IsNull() { + err := prior.As(&priorMap) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Prior State Value", + "An unexpected error occurred while trying to convert the prior state value to a go map. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + } + + if configValLen > 0 { + newVals := make(map[string]tftypes.Value, configValLen) + for name, configEV := range configMap { + priorEV, inPrior := priorMap[name] + if !inPrior { + // if the prior value was unknown the map won't have any + // keys, so generate an unknown value. + if !prior.IsKnown() { + err := tftypes.ValidateValue(configEV.Type(), tftypes.UnknownValue) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Value Type", + "An unexpected error occurred while trying to create an unknown config value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + priorEV = tftypes.NewValue(configEV.Type(), tftypes.UnknownValue) + } else { + err := tftypes.ValidateValue(configEV.Type(), nil) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Value Type", + "An unexpected error occurred while trying to create a null config value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + priorEV = tftypes.NewValue(configEV.Type(), nil) + + } + } + + nestedDiags := diag.Diagnostics{} //nolint + newVals[name], nestedDiags = proposedNewNestedObjectAttributes(ctx, s, attr, path.WithElementKeyString(name), priorEV, configEV) + diags.Append(nestedDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + } + + err := tftypes.ValidateValue(config.Type(), newVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Value Type", + "An unexpected error occurred while trying to create new value of the config type. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + + return tftypes.Value{}, diags + } + + newVal = tftypes.NewValue(config.Type(), newVals) + } + + return newVal, diags +} + +func proposedNewListNested(ctx context.Context, s fwschema.Schema, attr fwschema.NestedAttribute, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + newVal := config + + configVals := make([]tftypes.Value, 0) + priorVals := make([]tftypes.Value, 0) + + configValLen := 0 + if !config.IsNull() { + err := config.As(&configVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Config Value", + "An unexpected error occurred while trying to convert the config value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + configValLen = len(configVals) + } + + if !prior.IsNull() { + err := prior.As(&priorVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Prior State Value", + "An unexpected error occurred while trying to convert the prior state value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + } + + if configValLen > 0 { + newVals := make([]tftypes.Value, 0, configValLen) + for idx, configEV := range configVals { + if prior.IsKnown() && (prior.IsNull() || idx >= len(priorVals)) { + // No corresponding prior element, take config val + newVals = append(newVals, configEV) + continue + } + + priorEV := priorVals[idx] + newNestedVals, newNestedValDiags := proposedNewNestedObjectAttributes(ctx, s, attr, path.WithElementKeyInt(idx), priorEV, configEV) + diags.Append(newNestedValDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + newVals = append(newVals, newNestedVals) + } + + err := tftypes.ValidateValue(config.Type(), newVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid List Nested Attribute Value Type", + "An unexpected error occurred while trying to create a list nested attribute value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + newVal = tftypes.NewValue(config.Type(), newVals) + } + + return newVal, diags +} + +func proposedNewSetNested(ctx context.Context, s fwschema.Schema, attr fwschema.NestedAttribute, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + newVal := config + + configVals := make([]tftypes.Value, 0) + priorVals := make([]tftypes.Value, 0) + + configValLen := 0 + if !config.IsNull() { + err := config.As(&configVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Config Value", + "An unexpected error occurred while trying to convert the config value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + configValLen = len(configVals) + } + + if !prior.IsNull() { + err := prior.As(&priorVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Prior State Value", + "An unexpected error occurred while trying to convert the prior state value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + } + + if configValLen > 0 { + // track which prior elements have been used + used := make([]bool, len(priorVals)) + newVals := make([]tftypes.Value, 0, configValLen) + for _, configEV := range configVals { + var priorEV tftypes.Value + for i, priorCmp := range priorVals { + if used[i] { + continue + } + + // It is possible that multiple prior elements could be valid + // matches for a configuration value, in which case we will end up + // picking the first match encountered (but it will always be + // consistent due to cty's iteration order). Because configured set + // elements must also be entirely unique in order to be included in + // the set, these matches either will not matter because they only + // differ by computed values, or could not have come from a valid + // config with all unique set elements. + if validPriorFromConfig(ctx, s, path, priorCmp, configEV) { + priorEV = priorCmp + used[i] = true + break + } + } + + if priorEV.IsNull() { + err := tftypes.ValidateValue(attr.GetNestedObject().Type().TerraformType(ctx), nil) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Value Type", + "An unexpected error occurred while trying to create an null prior state value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + priorEV = tftypes.NewValue(attr.GetNestedObject().Type().TerraformType(ctx), nil) + } + newNestedVals, newNestedValDiags := proposedNewNestedObjectAttributes(ctx, s, attr, path.WithElementKeyValue(priorEV), priorEV, configEV) + diags.Append(newNestedValDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + newVals = append(newVals, newNestedVals) + } + err := tftypes.ValidateValue(config.Type(), newVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Set Nested Attribute Value Type", + "An unexpected error occurred while trying to create a set nested attribute value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + newVal = tftypes.NewValue(config.Type(), newVals) + } + + return newVal, diags +} + +func proposedNewNestedObjectAttributes(ctx context.Context, s fwschema.Schema, attr fwschema.NestedAttribute, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + if config.IsNull() { + return config, diags + } + + objType := attr.GetNestedObject().Type().TerraformType(ctx) + newAttrs, newAttrsDiags := proposedNewAttributes(ctx, s, attr.GetNestedObject().GetAttributes(), path, prior, config) + diags.Append(newAttrsDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + + err := tftypes.ValidateValue( + objType, + newAttrs, + ) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Nested Attribute Value Type", + "An unexpected error occurred while trying to create a nested attribute value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + return tftypes.NewValue( + objType, + newAttrs, + ), diags +} + +func proposeNewNestedBlock(ctx context.Context, s fwschema.Schema, block fwschema.Block, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + + // if the config isn't known at all, then we must use that value + if !config.IsKnown() { + return config, diags + } + + newVal := config + + switch block.GetNestingMode() { + case fwschema.BlockNestingModeSingle: + if config.IsNull() { + break + } + blockDiags := diag.Diagnostics{} //nolint + newVal, blockDiags = proposedNewNestedBlockObjectAttributes(ctx, s, block, path, prior, config) + diags.Append(blockDiags...) + if blockDiags.HasError() { + return tftypes.Value{}, diags + } + case fwschema.BlockNestingModeList: + blockDiags := diag.Diagnostics{} //nolint + newVal, blockDiags = proposedNewBlockListNested(ctx, s, block, path, prior, config) + diags.Append(blockDiags...) + if blockDiags.HasError() { + return tftypes.Value{}, diags + } + case fwschema.BlockNestingModeSet: + blockDiags := diag.Diagnostics{} //nolint + newVal, blockDiags = proposedNewBlockSetNested(ctx, s, block, path, prior, config) + diags.Append(blockDiags...) + if blockDiags.HasError() { + return tftypes.Value{}, diags + } + default: + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Block Nesting Mode", + "An unexpected error occurred while trying to construct the proposed new state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", fmt.Sprintf("unsupported attribute nesting mode %d", block.GetNestingMode())))) + + return tftypes.Value{}, diags + } + + return newVal, diags +} + +func proposedNewNestedBlockObjectAttributes(ctx context.Context, s fwschema.Schema, block fwschema.Block, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + if config.IsNull() { + return config, diags + } + valuesMap, attrDiags := proposedNewAttributes(ctx, s, block.GetNestedObject().GetAttributes(), path, prior, config) + diags.Append(attrDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + + for name, blockType := range block.GetNestedObject().GetBlocks() { + attrVal, err := prior.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Attribute Path", + "An unexpected error occurred while trying to retrieve a value from prior state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + priorVal := attrVal.(tftypes.Value) //nolint + + attrVal, err = config.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Config Attribute Path", + "An unexpected error occurred while trying to retrieve a value from config. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + configVal := attrVal.(tftypes.Value) //nolint + + nestedBlockDiags := diag.Diagnostics{} //nolint + valuesMap[name], nestedBlockDiags = proposeNewNestedBlock(ctx, s, blockType, tftypes.NewAttributePath().WithAttributeName(name).WithElementKeyInt(0), priorVal, configVal) + diags.Append(nestedBlockDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + } + + objType := block.GetNestedObject().Type().TerraformType(ctx) + + err := tftypes.ValidateValue( + objType, + valuesMap, + ) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Nested Block Object Value Type", + "An unexpected error occurred while trying to create a nested block object value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + return tftypes.NewValue( + objType, + valuesMap, + ), diags +} + +func proposedNewBlockListNested(ctx context.Context, s fwschema.Schema, block fwschema.Block, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + newVal := config + + configVals := make([]tftypes.Value, 0) + priorVals := make([]tftypes.Value, 0) + + configValLen := 0 + if !config.IsNull() { + err := config.As(&configVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Config Value", + "An unexpected error occurred while trying to convert the config value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + configValLen = len(configVals) + } + + if !prior.IsNull() { + err := prior.As(&priorVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Prior State Value", + "An unexpected error occurred while trying to convert the prior state value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + } + + if configValLen > 0 { + newVals := make([]tftypes.Value, 0, configValLen) + for idx, configEV := range configVals { + if prior.IsKnown() && (prior.IsNull() || idx >= len(priorVals)) { + // No corresponding prior element, take config val + newVals = append(newVals, configEV) + continue + } + + priorEV := priorVals[idx] + newNestedVal, newNestedValDiags := proposedNewNestedBlockObjectAttributes(ctx, s, block, path.WithElementKeyInt(idx), priorEV, configEV) + diags.Append(newNestedValDiags...) + if diags.HasError() { + return tftypes.Value{}, nil + } + newVals = append(newVals, newNestedVal) + } + + err := tftypes.ValidateValue(config.Type(), newVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid List Nested Block Value Type", + "An unexpected error occurred while trying to create a list nested block value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + newVal = tftypes.NewValue(config.Type(), newVals) + } + + return newVal, diags +} + +func proposedNewBlockSetNested(ctx context.Context, s fwschema.Schema, block fwschema.Block, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + newVal := config + + configVals := make([]tftypes.Value, 0) + priorVals := make([]tftypes.Value, 0) + + configValLen := 0 + if !config.IsNull() { + err := config.As(&configVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Config Value", + "An unexpected error occurred while trying to convert the config value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + configValLen = len(configVals) + } + + if !prior.IsNull() { + err := prior.As(&priorVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Error Converting Prior State Value", + "An unexpected error occurred while trying to convert the prior state value to a go list. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + } + + if configValLen > 0 { + // track which prior elements have been used + used := make([]bool, len(priorVals)) + newVals := make([]tftypes.Value, 0, configValLen) + for _, configEV := range configVals { + var priorEV tftypes.Value + for i, priorCmp := range priorVals { + if used[i] { + continue + } + + // It is possible that multiple prior elements could be valid + // matches for a configuration value, in which case we will end up + // picking the first match encountered (but it will always be + // consistent due to cty's iteration order). Because configured set + // elements must also be entirely unique in order to be included in + // the set, these matches either will not matter because they only + // differ by computed values, or could not have come from a valid + // config with all unique set elements. + if validPriorFromConfig(ctx, s, path, priorCmp, configEV) { + priorEV = priorCmp + used[i] = true + break + } + } + + if priorEV.IsNull() { + err := tftypes.ValidateValue(block.GetNestedObject().Type().TerraformType(ctx), nil) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Value Type", + "An unexpected error occurred while trying to create an null prior state value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + priorEV = tftypes.NewValue(block.GetNestedObject().Type().TerraformType(ctx), nil) + } + newNestedVal, newNestedValDiags := proposeNewNestedBlockObject(ctx, s, block.GetNestedObject(), path.WithElementKeyValue(priorEV), priorEV, configEV) + diags.Append(newNestedValDiags...) + if diags.HasError() { + return tftypes.Value{}, nil + } + + newVals = append(newVals, newNestedVal) + } + + err := tftypes.ValidateValue(config.Type(), newVals) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Set Nested Block Value Type", + "An unexpected error occurred while trying to create a set nested block value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + newVal = tftypes.NewValue(config.Type(), newVals) + } + + return newVal, diags +} + +func proposeNewNestedBlockObject(ctx context.Context, s fwschema.Schema, nestedBlock fwschema.NestedBlockObject, path *tftypes.AttributePath, prior, config tftypes.Value) (tftypes.Value, diag.Diagnostics) { + diags := diag.Diagnostics{} + + if config.IsNull() { + return config, diags + } + valuesMap, attrDiags := proposedNewAttributes(ctx, s, nestedBlock.GetAttributes(), path, prior, config) + diags.Append(attrDiags...) + if diags.HasError() { + return tftypes.Value{}, diags + } + + for name, blockType := range nestedBlock.GetBlocks() { + var priorVal tftypes.Value + if prior.IsNull() { + priorObjType := prior.Type().(tftypes.Object) //nolint + + err := tftypes.ValidateValue(priorObjType.AttributeTypes[name], nil) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Value Type", + "An unexpected error occurred while trying to validate a value from prior state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + priorVal = tftypes.NewValue(priorObjType.AttributeTypes[name], nil) + } else { + attrVal, err := prior.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Prior State Attribute Path", + "An unexpected error occurred while trying to retrieve a value from prior state. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + priorVal = attrVal.(tftypes.Value) //nolint + } + + attrVal, _ := config.ApplyTerraform5AttributePathStep(tftypes.AttributeName(name)) + configVal := attrVal.(tftypes.Value) //nolint + + nestedBlockDiags := diag.Diagnostics{} //nolint + valuesMap[name], nestedBlockDiags = proposeNewNestedBlock(ctx, s, blockType, path.WithAttributeName(name), priorVal, configVal) + diags.Append(nestedBlockDiags...) + if nestedBlockDiags.HasError() { + return tftypes.Value{}, diags + } + + } + + err := tftypes.ValidateValue(nestedBlock.Type().TerraformType(ctx), valuesMap) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, path, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Nested Block Value Type", + "An unexpected error occurred while trying to create a nested block value. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + return tftypes.Value{}, diags + } + + return tftypes.NewValue( + nestedBlock.Type().TerraformType(ctx), + valuesMap, + ), diags +} + +func optionalValueNotComputable(ctx context.Context, s fwschema.Schema, absPath *tftypes.AttributePath, val tftypes.Value) (bool, diag.Diagnostics) { + diags := diag.Diagnostics{} + attr, err := s.AttributeAtTerraformPath(ctx, absPath) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, absPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Attribute Path", + "An unexpected error occurred while trying to retrieve attribute at path. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + + return false, diags + } + + if !attr.IsOptional() { //nolint + return false, diags + } + + _, nested := attr.(fwschema.NestedAttribute) + if !nested { + return false, diags + } + + foundNonComputedAttr := false + err = tftypes.Walk(val, func(path *tftypes.AttributePath, v tftypes.Value) (bool, error) { //nolint + if v.IsNull() { + return true, nil + } + + // Continue past the root + if len(path.Steps()) < 1 { + return true, nil + } + + attrPath := tftypes.NewAttributePathWithSteps(append(absPath.Steps(), path.Steps()...)) + attrSchema, err := s.AttributeAtTerraformPath(ctx, attrPath) + if err != nil { + return true, nil //nolint + } + + if !attrSchema.IsComputed() { + foundNonComputedAttr = true + return false, nil + } + + return true, nil + }) + if err != nil { + fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, absPath, s) + diags.Append(fwPathDiags...) + + diags.Append(diag.NewAttributeErrorDiagnostic(fwPath, + "Invalid Attribute Path", + "An unexpected error occurred while trying to walk the value at path. "+ + "This is an error in terraform-plugin-framework used by the provider. "+ + "Please report the following to the provider developers.\n\n"+ + fmt.Sprintf("Original Error: %s", err), + )) + + } + + return foundNonComputedAttr, diags +} + +// validPriorFromConfig returns true if the prior object could have been +// derived from the configuration. We do this by walking the prior value to +// determine if it is a valid superset of the config, and only computable +// values have been added. This function is only used to correlated +// configuration with possible valid prior values within sets. +func validPriorFromConfig(ctx context.Context, s fwschema.Schema, absPath *tftypes.AttributePath, prior, config tftypes.Value) bool { + if config.Equal(prior) { + return true + } + + // error value to halt the walk + stop := errors.New("stop") + + valid := true + _ = tftypes.Walk(prior, func(path *tftypes.AttributePath, priorV tftypes.Value) (bool, error) { + if priorV.IsNull() { + return true, nil + } + + // Continue past the root + if len(path.Steps()) < 1 { + return true, nil + } + + configIface, _, err := tftypes.WalkAttributePath(config, path) + if err != nil { + // most likely dynamic objects with different types + valid = false + return false, stop + } + configV := configIface.(tftypes.Value) //nolint + + // we don't need to know the schema if both are equal + if configV.Equal(priorV) { + // we know they are equal, so no need to descend further + return false, nil + } + + // We can't descend into nested sets to correlate configuration, so the + // overall values must be equal. + if configV.Type().Is(tftypes.Set{}) { + valid = false + return false, stop + } + setValPath := tftypes.NewAttributePath().WithElementKeyValue(prior) + + attrPath := tftypes.NewAttributePathWithSteps(append(absPath.Steps(), append(setValPath.Steps(), path.Steps()...)...)) + attrSchema, err := s.AttributeAtTerraformPath(ctx, attrPath) + if err != nil { + // Not at a schema attribute, so we can continue until we find leaf + // attributes. + return true, nil //nolint + } + + // If we have nested object attributes we'll be descending into those + // to compare the individual values and determine why this level is not + // equal + _, isNestedType := attrSchema.GetType().(attr.TypeWithAttributeTypes) + if isNestedType { + return true, nil + } + + // This is a leaf attribute, so it must be computed in order to differ + // from config. + if !attrSchema.IsComputed() { + valid = false + return false, stop + } + + // And if it is computed, the config must be null to allow a change. + if !configV.IsNull() { + valid = false + return false, stop + } + + // We sill stop here. The cty value could be far larger, but this was + // the last level of prescribed schema. + return false, nil + }) + + return valid +} diff --git a/internal/fwserver/schema_propose_new_plan_test.go b/internal/fwserver/schema_propose_new_plan_test.go new file mode 100644 index 000000000..266a9a3d1 --- /dev/null +++ b/internal/fwserver/schema_propose_new_plan_test.go @@ -0,0 +1,5806 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package fwserver + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +func TestSchemaProposeNewState(t *testing.T) { + t.Parallel() + tests := map[string]struct { + schema fwschema.Schema + priorVal map[string]tftypes.Value + configVal map[string]tftypes.Value + expectedVal map[string]tftypes.Value + }{ + "empty": { + schema: schema.Schema{}, + priorVal: map[string]tftypes.Value{}, + configVal: map[string]tftypes.Value{}, + expectedVal: map[string]tftypes.Value{}, + }, + "no prior": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "optional_attribute": schema.StringAttribute{ + Optional: true, + }, + "computed_attribute": schema.StringAttribute{ + Computed: true, + }, + "single_nested_attribute": schema.SingleNestedAttribute{ + Computed: true, + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "single_nested_block": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "optional_computed_attributeA": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_attributeB": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + priorVal: nil, + configVal: map[string]tftypes.Value{ + "optional_attribute": tftypes.NewValue(tftypes.String, "hello"), + "computed_attribute": tftypes.NewValue(tftypes.String, nil), + "single_nested_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"required_nested_attribute": tftypes.String}}, nil), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "world"), + // An unknown in the config represents a situation where + // an argument is explicitly set to an expression result + // that is derived from an unknown value. This is distinct + // from leaving it null, which allows the provider itself + // to decide the value during PlanResourceChange. + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + }, + expectedVal: map[string]tftypes.Value{ + "optional_attribute": tftypes.NewValue(tftypes.String, "hello"), + // unset computed attributes are null in the proposal; provider + // usually changes them to "unknown" during PlanResourceChange, + // to indicate that the value will be decided during apply. + "computed_attribute": tftypes.NewValue(tftypes.String, nil), + "single_nested_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"required_nested_attribute": tftypes.String}}, nil), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "world"), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), // explicit unknown preserved from config + }), + }, + }, + "null block remains null": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "optional_attribute": schema.StringAttribute{ + Optional: true, + }, + "single_nested_attribute": schema.SingleNestedAttribute{ + Computed: true, + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "single_nested_block": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "optional_computed_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + priorVal: nil, + configVal: map[string]tftypes.Value{ + "optional_attribute": tftypes.NewValue(tftypes.String, "bar"), + "single_nested_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"required_nested_attribute": tftypes.String}}, nil), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute": tftypes.String, + }, + }, nil), + }, + expectedVal: map[string]tftypes.Value{ + "optional_attribute": tftypes.NewValue(tftypes.String, "bar"), + "single_nested_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"required_nested_attribute": tftypes.String}}, nil), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute": tftypes.String, + }, + }, nil), + }, + }, + "no prior with set": { + // This one is here because our handling of sets is more complex + // than others (due to the fuzzy correlation heuristic) and + // historically that caused us some panic-related grief. + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: nil, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "world"), + }), + }, + ), + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "world"), + }), + }, + ), + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + }), + }, + ), + }, + }, + "prior attributes": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "optional_attribute": schema.StringAttribute{ + Optional: true, + }, + "computed_attribute": schema.StringAttribute{ + Computed: true, + }, + "optional_computed_attributeA": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_attributeB": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "single_nested_attribute": schema.SingleNestedAttribute{ + Computed: true, + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "optional_attribute": tftypes.NewValue(tftypes.String, "bonjour"), + "computed_attribute": tftypes.NewValue(tftypes.String, "petit dejeuner"), + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "grande dejeuner"), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, "a la monde"), + "single_nested_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"required_nested_attribute": tftypes.String}}, + map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + }), + }, + configVal: map[string]tftypes.Value{ + "optional_attribute": tftypes.NewValue(tftypes.String, "hello"), + "computed_attribute": tftypes.NewValue(tftypes.String, nil), + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, nil), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, "world"), + "single_nested_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"required_nested_attribute": tftypes.String}}, + map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "bleep"), + }), + }, + expectedVal: map[string]tftypes.Value{ + "optional_attribute": tftypes.NewValue(tftypes.String, "hello"), + "computed_attribute": tftypes.NewValue(tftypes.String, "petit dejeuner"), + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "grande dejeuner"), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, "world"), + "single_nested_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"required_nested_attribute": tftypes.String}}, + map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "bleep"), + }), + }, + }, + "prior nested single": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "single_nested_block": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "optional_computed_attributeA": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_attributeB": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "bleep"), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, "boop"), + }), + }, + configVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + }), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "bap"), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, nil), + }), + }, + expectedVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + }), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "bap"), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, "boop"), + }), + }, + }, + "prior nested single to null": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "single_nested_block": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "optional_computed_attributeA": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_attributeB": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_attributeA": tftypes.NewValue(tftypes.String, "bleep"), + "optional_computed_attributeB": tftypes.NewValue(tftypes.String, "boop"), + }), + }, + configVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, nil), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, nil), + }, + expectedVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, nil), + "single_nested_block": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attributeA": tftypes.String, + "optional_computed_attributeB": tftypes.String, + }, + }, nil), + }, + }, + "prior optional computed nested single to null": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + configVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, nil), + }, + expectedVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, nil), + }, + }, + "prior nested list": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "list_nested_attribute": schema.ListNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "list_nested_block": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "optional_computed_nested_attributeA": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_nested_attributeB": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "bar"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "baz"), + }), + }, + ), + "list_nested_block": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attributeA": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_attributeB": tftypes.NewValue(tftypes.String, "boop"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "bar"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "baz"), + }), + }, + ), + "list_nested_block": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attributeA": tftypes.NewValue(tftypes.String, "bap"), + "optional_computed_nested_attributeB": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attributeA": tftypes.NewValue(tftypes.String, "blep"), + "optional_computed_nested_attributeB": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "bar"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "baz"), + }), + }, + ), + "list_nested_block": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attributeA": tftypes.NewValue(tftypes.String, "bap"), + "optional_computed_nested_attributeB": tftypes.NewValue(tftypes.String, "boop"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attributeA": tftypes.String, + "optional_computed_nested_attributeB": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attributeA": tftypes.NewValue(tftypes.String, "blep"), + "optional_computed_nested_attributeB": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + }, + "prior nested list with dynamic": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "list_nested_attribute": schema.ListNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_dynamic_attributeA": schema.DynamicAttribute{ + Required: true, + }, + "required_nested_dynamic_attributeB": schema.DynamicAttribute{ + Required: true, + }, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "list_nested_block": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "optional_computed_nested_string_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_nested_dynamic_attribute": schema.DynamicAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_dynamic_attributeA": tftypes.DynamicPseudoType, + "required_nested_dynamic_attributeB": tftypes.DynamicPseudoType, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_dynamic_attributeA": tftypes.DynamicPseudoType, + "required_nested_dynamic_attributeB": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_dynamic_attributeA": tftypes.NewValue(tftypes.String, "bar"), + "required_nested_dynamic_attributeB": tftypes.NewValue(tftypes.String, "glup"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_dynamic_attributeA": tftypes.DynamicPseudoType, + "required_nested_dynamic_attributeB": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_dynamic_attributeA": tftypes.NewValue(tftypes.String, "baz"), + "required_nested_dynamic_attributeB": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + "list_nested_block": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_string_attribute": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_dynamic_attribute": tftypes.NewValue(tftypes.String, "boop"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_dynamic_attributeA": tftypes.DynamicPseudoType, + "required_nested_dynamic_attributeB": tftypes.DynamicPseudoType, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_dynamic_attributeA": tftypes.DynamicPseudoType, + "required_nested_dynamic_attributeB": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_dynamic_attributeA": tftypes.NewValue(tftypes.String, "bar"), + "required_nested_dynamic_attributeB": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + "list_nested_block": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_string_attribute": tftypes.NewValue(tftypes.String, "bap"), + "optional_computed_nested_dynamic_attribute": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_string_attribute": tftypes.NewValue(tftypes.String, "blep"), + "optional_computed_nested_dynamic_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_dynamic_attributeA": tftypes.DynamicPseudoType, + "required_nested_dynamic_attributeB": tftypes.DynamicPseudoType, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_dynamic_attributeA": tftypes.DynamicPseudoType, + "required_nested_dynamic_attributeB": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_dynamic_attributeA": tftypes.NewValue(tftypes.String, "bar"), + "required_nested_dynamic_attributeB": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + "list_nested_block": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_string_attribute": tftypes.NewValue(tftypes.String, "bap"), + "optional_computed_nested_dynamic_attribute": tftypes.NewValue(tftypes.String, "boop"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_string_attribute": tftypes.String, + "optional_computed_nested_dynamic_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_string_attribute": tftypes.NewValue(tftypes.String, "blep"), + "optional_computed_nested_dynamic_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + }, + "prior nested map": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "map_nested_attribute": schema.MapNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + }), + "b": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + }), + "c": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + }), + "c": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + }), + }, + ), + }, + }, + "prior optional computed nested map elem to null": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "map_nested_attribute": schema.MapNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "computed"), + }), + "b": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "computed"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, nil), + "c": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, nil), + "c": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + }, + "prior optional computed nested map to null": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "map_nested_attribute": schema.MapNestedAttribute{ + Optional: true, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "computed"), + }), + "b": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "blub"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "computed"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + nil, + ), + }, + expectedVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + nil, + ), + }, + }, + "prior nested map with dynamic": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "map_nested_attribute": schema.MapNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.DynamicAttribute{ + Required: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + }), + "b": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.Number, 13), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "blep"), + }), + "c": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.Number, 13), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + map[string]tftypes.Value{ + "a": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "blep"), + }), + "c": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.Number, 13), + }), + }, + ), + }, + }, + "prior nested set": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + // This non-computed attribute will serve + // as our matching key for propagating + // "optional_computed_nested_attribute" from elements in the prior value. + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glubglub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glubglub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + }), + }, + ), + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "boop"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "blep"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "boot"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glubglub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "bosh"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glubglub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "glub"), + "optional_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "boop"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "bosh"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + }, + "set with partial optional computed change": { + schema: schema.Schema{ + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "OK"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "OK"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "replaced"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "OK"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "replaced"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + }, + "set without partial optional computed change": { + schema: schema.Schema{ + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "two"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "one"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "two"), + }), + }, + ), + }, + }, + "sets differing only by unknown": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + }, + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: nil, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + }, + ), + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + // These remain distinct because unknown values never + // compare equal. They may be consolidated together once + // the values become known, though. + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + }, + ), + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + }), + }, + ), + }, + }, + "nested list in set": { + schema: schema.Schema{ + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "nested_list_block": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "nested_attribute": schema.StringAttribute{}, + "optional_computed_nested_attribute": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }}, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "boop"), + }), + }), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }}, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, nil), + }), + }), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }}, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + "optional_computed_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "beep"), + "optional_computed_nested_attribute": tftypes.NewValue(tftypes.String, "boop"), + }), + }), + }), + }, + ), + }, + }, + // TODO: figure out if we need this test + // The set value is panicking because there are multiple types defined in the set. + // tftypes seems to treat each definition of the `nested_list_block` type as separate types, + // possibly because it has no attributes defined in the nested block object for equality comparison. + //"empty nested list in set": { + // schema: schema.Schema{ + // Blocks: map[string]schema.Block{ + // "set_nested_block": schema.SetNestedBlock{ + // NestedObject: schema.NestedBlockObject{ + // Blocks: map[string]schema.Block{ + // "nested_list_block": schema.ListNestedBlock{ + // NestedObject: schema.NestedBlockObject{}, + // }, + // }, + // }, + // }, + // }, + // }, + // priorVal: map[string]tftypes.Value{ + // "set_nested_block": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "nested_list_block": tftypes.List{ + // ElementType: tftypes.Object{}, + // }, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "nested_list_block": tftypes.List{ + // ElementType: tftypes.Object{}, + // }, + // }, + // }, map[string]tftypes.Value{ + // "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{}}, []tftypes.Value{}), + // }), + // }, + // ), + // }, + // configVal: map[string]tftypes.Value{ + // "set_nested_block": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "nested_list_block": tftypes.List{ + // ElementType: tftypes.Object{}, + // }, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "nested_list_block": tftypes.List{ + // ElementType: tftypes.Object{}, + // }, + // }, + // }, map[string]tftypes.Value{ + // "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{}}, []tftypes.Value{}), + // }), + // }, + // ), + // }, + // expectedVal: map[string]tftypes.Value{ + // "set_nested_block": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "nested_list_block": tftypes.List{ + // ElementType: tftypes.Object{}, + // }, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "nested_list_block": tftypes.List{ + // ElementType: tftypes.Object{}, + // }, + // }, + // }, map[string]tftypes.Value{ + // "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{}}, []tftypes.Value{}), + // }), + // }, + // ), + // }, + //}, + "nested list with dynamic in set": { + schema: schema.Schema{ + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "nested_list_block": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "nested_attribute": schema.DynamicAttribute{}, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }}, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, + []tftypes.Value{ + tftypes.NewValue(tftypes.String, "true"), + }), + }), + }), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }}, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, + []tftypes.Value{ + tftypes.NewValue(tftypes.String, "true"), + }), + }), + }), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_block": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_list_block": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }}, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, + []tftypes.Value{ + tftypes.NewValue(tftypes.String, "true"), + }, + ), + }), + }), + }), + }, + ), + }, + }, + "nested map with dynamic in set": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_map_attribute": schema.MapNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_attribute": schema.DynamicAttribute{ + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_map_attribute": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, map[string]tftypes.Value{ + "bing": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + "bang": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, + []tftypes.Value{ + tftypes.NewValue(tftypes.String, "true"), + }, + ), + }), + }), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_map_attribute": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, map[string]tftypes.Value{ + "bing": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, + []tftypes.Value{ + tftypes.NewValue(tftypes.String, "true"), + }, + ), + }), + }), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_map_attribute": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, + }, map[string]tftypes.Value{ + "bing": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.DynamicPseudoType, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, + []tftypes.Value{ + tftypes.NewValue(tftypes.String, "true"), + }, + ), + }), + }), + }), + }, + ), + }, + }, + "empty nested map in set": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_map_attribute": schema.MapNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_map_attribute": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, map[string]tftypes.Value{}), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_map_attribute": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, map[string]tftypes.Value{ + "bing": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + }), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_map_attribute": tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_map_attribute": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, + }, map[string]tftypes.Value{ + "bing": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "nested_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + }), + }), + }, + ), + }, + }, + // This example has a mixture of optional, computed and required in a deeply-nested NestedType attribute + "deeply NestedType": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "required_single_nested_nested_attribute": schema.SingleNestedAttribute{ + Attributes: testAttributes, + Required: true, + }, + "optional_single_nested_nested_attribute": schema.SingleNestedAttribute{ + Attributes: testAttributes, + Optional: true, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_single_nested_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + "optional_single_nested_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "required_single_nested_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, nil), + "optional_single_nested_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, nil), + "computed": tftypes.NewValue(tftypes.String, "hello"), + "optional_computed": tftypes.NewValue(tftypes.String, "prior"), + "required": tftypes.NewValue(tftypes.String, "present"), + }), + }), + }, + configVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_single_nested_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + "optional_single_nested_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "required_single_nested_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, tftypes.UnknownValue), // explicit unknown from config + "optional_single_nested_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, nil), + "computed": tftypes.NewValue(tftypes.String, nil), + "optional_computed": tftypes.NewValue(tftypes.String, "hello"), + "required": tftypes.NewValue(tftypes.String, "present"), + }), + }), + }, + expectedVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_single_nested_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + "optional_single_nested_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "required_single_nested_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, tftypes.UnknownValue), // explicit unknown preserved from the config + "optional_single_nested_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, nil), // config is null + "computed": tftypes.NewValue(tftypes.String, "hello"), // computed values come from prior + "optional_computed": tftypes.NewValue(tftypes.String, "hello"), // config takes precedent over prior in opt+computed + "required": tftypes.NewValue(tftypes.String, "present"), // value from config + }), + }), + }, + }, + "deeply nested set": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_set_nested_attribute": schema.SetNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: testAttributes, + }, + Required: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_set_nested_attribute": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "prior"), + "computed": tftypes.NewValue(tftypes.String, "prior"), + "optional_computed": tftypes.NewValue(tftypes.String, "prior"), + "required": tftypes.NewValue(tftypes.String, "prior"), + }), + }), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_set_nested_attribute": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "other_prior"), + "computed": tftypes.NewValue(tftypes.String, "other_prior"), + "optional_computed": tftypes.NewValue(tftypes.String, "other_prior"), + "required": tftypes.NewValue(tftypes.String, "other_prior"), + }), + }), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_set_nested_attribute": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "configured"), + "computed": tftypes.NewValue(tftypes.String, nil), // computed attrs are null in config + "optional_computed": tftypes.NewValue(tftypes.String, "configured"), + "required": tftypes.NewValue(tftypes.String, "configured"), + }), + }), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_set_nested_attribute": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, nil), // explicit null in config + "computed": tftypes.NewValue(tftypes.String, nil), // computed attrs are null in config + "optional_computed": tftypes.NewValue(tftypes.String, "other_configured"), + "required": tftypes.NewValue(tftypes.String, "other_configured"), + }), + }), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_set_nested_attribute": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "configured"), + "computed": tftypes.NewValue(tftypes.String, nil), + "optional_computed": tftypes.NewValue(tftypes.String, "configured"), + "required": tftypes.NewValue(tftypes.String, "configured"), + }), + }), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, map[string]tftypes.Value{ + "nested_set_nested_attribute": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, nil), // explicit null in config is preserved + "computed": tftypes.NewValue(tftypes.String, nil), + "optional_computed": tftypes.NewValue(tftypes.String, "other_configured"), + "required": tftypes.NewValue(tftypes.String, "other_configured"), + }), + }), + }), + }, + ), + }, + }, + "expected null NestedTypes": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + "list_nested_attribute": schema.ListNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + "map_nested_attribute": schema.MapNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + "nested_map_nested_attribute": schema.MapNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "inner_nested_single_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: testAttributes, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "baz"), + }), + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "baz"), + }), + }, + ), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "baz"), + }), + }, + ), + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "map_entry": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "baz"), + }), + }, + ), + "nested_map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "inner_nested_single_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "map_entry": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "inner_nested_single_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, map[string]tftypes.Value{ + "inner_nested_single_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "foo"), // explicit null in config is preserved + "computed": tftypes.NewValue(tftypes.String, "foo"), + "optional_computed": tftypes.NewValue(tftypes.String, "foo"), + "required": tftypes.NewValue(tftypes.String, "foo"), + }), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, nil), + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, nil), + }, + ), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, nil), + }, + ), + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + nil, + ), + "nested_map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "inner_nested_single_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, + nil, + ), + }, + expectedVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, nil), + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, nil), + }, + ), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, nil), + }, + ), + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + nil, + ), + "nested_map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "inner_nested_single_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + "optional_computed": tftypes.String, + "required": tftypes.String, + }, + }, + }, + }, + }, + nil, + ), + }, + }, + "expected empty NestedTypes": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "list_nested_attribute": schema.ListNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{}, + ), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{}, + ), + }, + configVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{}, + ), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{}, + ), + }, + expectedVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{}, + ), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{}, + ), + }, + }, + "optional types set replacement": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "required_nested_attribute": schema.StringAttribute{ + Required: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "old"), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "new"), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "required_nested_attribute": tftypes.String, + }, + }, map[string]tftypes.Value{ + "required_nested_attribute": tftypes.NewValue(tftypes.String, "new"), + }), + }, + ), + }, + }, + "prior null nested objects": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "nested_list_nested_attribute": schema.ListNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + }, + }, + "map_nested_attribute": schema.MapNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_list_nested_attribute": schema.ListNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_nested_attribute": schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + }, + }, + nil, + ), + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + }, + }, + }, + map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + }}, + map[string]tftypes.Value{ + "nested_list_nested_attribute": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + []tftypes.Value{}), + }), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + }, + }, + map[string]tftypes.Value{ + "nested_list_nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "a"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "b"), + }), + }), + }, + ), + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + }, + }, + }, + map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + }}, + map[string]tftypes.Value{ + "nested_list_nested_attribute": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "a"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "b"), + }), + }), + }), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + }, + }, + map[string]tftypes.Value{ + "nested_list_nested_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "a"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "b"), + }), + }), + }, + ), + "map_nested_attribute": tftypes.NewValue( + tftypes.Map{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + }, + }, + }, + map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }, + }, + }}, + map[string]tftypes.Value{ + "nested_list_nested_attribute": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }, + }}, + []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "a"), + }), + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_nested_attribute": tftypes.String, + }}, map[string]tftypes.Value{ + "optional_nested_attribute": tftypes.NewValue(tftypes.String, "b"), + }), + }), + }), + }, + ), + }, + }, + + // Data sources are planned with an unknown value. + "unknown prior nested objects": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "list_nested_attribute": schema.ListNestedAttribute{ + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_list_nested_attribute": schema.ListNestedAttribute{ + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "string_attribute": schema.StringAttribute{}, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + tftypes.UnknownValue, + ), + }, + configVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + nil, + ), + }, + expectedVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_list_nested_attribute": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + }, + }, + }, + }, + tftypes.UnknownValue, + ), + }, + }, + + // A nested object with computed attributes, which is contained in an + // optional+computed container. The nested computed values should be + // represented in the proposed new object. + "config within optional+computed": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "list_nested_attribute": schema.ListNestedAttribute{ + Optional: true, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "nested_object": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "optional": schema.StringAttribute{ + Optional: true, + }, + "computed": schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_object": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_object": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "nested_object": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "prior"), + "computed": tftypes.NewValue(tftypes.String, "prior computed"), + }, + ), + }, + ), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_object": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_object": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "nested_object": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "prior"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "list_nested_attribute": tftypes.NewValue( + tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_object": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "nested_object": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "nested_object": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "prior"), + "computed": tftypes.NewValue(tftypes.String, "prior computed"), + }, + ), + }, + ), + }, + ), + }, + }, + + // A nested object with computed attributes, which is contained in an + // optional+computed set. The nested computed values should be + // represented in the proposed new object, and correlated with state + // via the non-computed attributes. + "config add within optional+computed set": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "optional": schema.StringAttribute{ + Optional: true, + }, + "computed": schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, "first computed"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "second"), + "computed": tftypes.NewValue(tftypes.String, "second computed"), + }, + ), + }, + ), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "second"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "third"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, "first computed"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "second"), + "computed": tftypes.NewValue(tftypes.String, "second computed"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "third"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + }, + }, + + // A nested object with computed attributes, which is contained in a + // set. The nested computed values should be represented in the + // proposed new object, and correlated with state via the non-computed + // attributes. + "config add within set block": { + schema: schema.Schema{ + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "optional": schema.StringAttribute{ + Optional: true, + }, + "computed": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, "first computed"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "second"), + "computed": tftypes.NewValue(tftypes.String, "second from config"), + }, + ), + }, + ), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "second"), + "computed": tftypes.NewValue(tftypes.String, "second from config"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "third"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, "first computed"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "second"), + "computed": tftypes.NewValue(tftypes.String, "second from config"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "third"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + }, + }, + + // A nested object with computed attributes, which is contained in a + // set. The nested computed values should be represented in the + // proposed new object, and correlated with state via the non-computed + // attributes. + "config change within set block": { + schema: schema.Schema{ + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "single_nested_attribute": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "optional": schema.StringAttribute{ + Optional: true, + }, + "computed": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, "first computed"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "second"), + "computed": tftypes.NewValue(tftypes.String, "second computed"), + }, + ), + }, + ), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "changed"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "first"), + "computed": tftypes.NewValue(tftypes.String, "first computed"), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "single_nested_attribute": tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + }, + map[string]tftypes.Value{ + "single_nested_attribute": tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "changed"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + }, + }, + + "set attr with partial optional computed change": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_block": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional": schema.StringAttribute{ + Optional: true, + }, + "computed": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "one"), + "computed": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "two"), + "computed": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "one"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "replaced"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "one"), + "computed": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "replaced"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + }, + + "set attr without optional computed change": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional": schema.StringAttribute{ + Optional: true, + }, + "computed": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "one"), + "computed": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "two"), + "computed": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "one"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "two"), + "computed": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "one"), + "computed": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional": tftypes.String, + "computed": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional": tftypes.NewValue(tftypes.String, "two"), + "computed": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + }, + + "set attr with all optional computed": { + schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_computed_attribute_a": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_attribute_b": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + // Each of these values can be correlated by the existence of the + // optional config attribute. Because "one" and "two" are set in + // the config, they must exist in the state regardless of + // optional&computed. + configVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, nil), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + }, + + "set block with all optional computed and nested object types": { + schema: schema.Schema{ + Blocks: map[string]schema.Block{ + "set_nested_block": schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "optional_computed_attribute_a": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_attribute_b": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "set_nested_attribute": schema.SetNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "optional_computed_attribute_a": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "optional_computed_attribute_b": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + priorVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + ), + }, + ), + }, + configVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, nil), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "three"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, nil), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + nil, + ), + }, + ), + }, + ), + }, + expectedVal: map[string]tftypes.Value{ + "set_nested_block": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + }, + []tftypes.Value{ + // We can correlate this with prior from the outer object + // attributes, and the equal nested set. + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "one"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + }, + ), + }, + ), + }, + ), + // This value is overridden by config, because we can't + // correlate optional+computed config values within nested + // sets. + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, "OK"), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + []tftypes.Value{ + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "two"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + ), + }, + ), + // This value was taken only from config + tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + "set_nested_attribute": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + }, + }, + map[string]tftypes.Value{ + "optional_computed_attribute_a": tftypes.NewValue(tftypes.String, "three"), + "optional_computed_attribute_b": tftypes.NewValue(tftypes.String, nil), + "set_nested_attribute": tftypes.NewValue( + tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "optional_computed_attribute_a": tftypes.String, + "optional_computed_attribute_b": tftypes.String, + }, + }, + }, + nil, + ), + }, + ), + }, + ), + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + t.Parallel() + priorStateVal := tftypes.NewValue(tftypes.DynamicPseudoType, nil) + if test.priorVal != nil { + schemaType := test.schema.Type().TerraformType(context.Background()) + priorStateVal = tftypes.NewValue(schemaType, test.priorVal) + } + + request := ProposeNewStateRequest{ + PriorState: tfsdk.State{ + Raw: priorStateVal, + Schema: test.schema, + }, + Config: tfsdk.Config{ + Raw: tftypes.NewValue(test.schema.Type().TerraformType(context.Background()), test.configVal), + Schema: test.schema, + }, + } + expectedResponse := &ProposeNewStateResponse{ + ProposedNewState: tfsdk.Plan{ + Raw: tftypes.NewValue(test.schema.Type().TerraformType(context.Background()), test.expectedVal), + Schema: test.schema, + }, + } + response := &ProposeNewStateResponse{} + SchemaProposeNewState(context.TODO(), test.schema, request, response) + if diff := cmp.Diff(response, expectedResponse); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +var testAttributes = map[string]schema.Attribute{ + "optional": schema.StringAttribute{ + Optional: true, + }, + "computed": schema.StringAttribute{ + Computed: true, + }, + "optional_computed": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "required": schema.StringAttribute{ + Required: true, + }, +} diff --git a/internal/fwserver/server_planresourcechange.go b/internal/fwserver/server_planresourcechange.go index 772c8c9bc..67fdde73f 100644 --- a/internal/fwserver/server_planresourcechange.go +++ b/internal/fwserver/server_planresourcechange.go @@ -150,7 +150,30 @@ func (s *Server) PlanResourceChange(ctx context.Context, req *PlanResourceChange } } - resp.PlannedState = planToState(*req.ProposedNewState) + // Propose new plan from prior state and config + proposeNewPlanReq := ProposeNewStateRequest{ + PriorState: *req.PriorState, + Config: *req.Config, + } + + proposeNewPlanResp := ProposeNewStateResponse{} + + SchemaProposeNewState(ctx, req.ResourceSchema, proposeNewPlanReq, &proposeNewPlanResp) + + resp.Diagnostics.Append(proposeNewPlanResp.Diagnostics...) + if resp.Diagnostics.HasError() { + return + } + + // New proposed plan + resp.PlannedState = planToState(proposeNewPlanResp.ProposedNewState) + + if !resp.PlannedState.Raw.Equal(req.ProposedNewState.Raw) { + panic("WHOA! There is a diff between Terraform core's proposed new state and the framework proposed new state :D") + } + + // Old proposed plan + // resp.PlannedState = planToState(*req.ProposedNewState) // Set Defaults. // diff --git a/internal/fwserver/server_planresourcechange_test.go b/internal/fwserver/server_planresourcechange_test.go index bd757e02c..267d2c3ef 100644 --- a/internal/fwserver/server_planresourcechange_test.go +++ b/internal/fwserver/server_planresourcechange_test.go @@ -428,8 +428,8 @@ func TestServerPlanResourceChange(t *testing.T) { // float32 which may result in accuracy loss. var float32Value float32 = 1.2 var computedFloat32Value float32 = 1.2345 - var updatedFloat32Value float32 = 5.4321 - var configuredFloat32Value float32 = 2.4 + //var updatedFloat32Value float32 = 5.4321 + //var configuredFloat32Value float32 = 2.4 testSchemaType := tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ @@ -3758,7 +3758,7 @@ func TestServerPlanResourceChange(t *testing.T) { Config: &tfsdk.Config{ Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), + "test_required": tftypes.NewValue(tftypes.String, nil), }), Schema: testSchema, }, @@ -3794,10 +3794,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -3836,10 +3833,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -3874,10 +3868,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -3913,10 +3904,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -3950,10 +3938,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -3997,10 +3982,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -4040,10 +4022,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -4097,10 +4076,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -4148,10 +4124,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -4191,10 +4164,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaType, nil), Schema: testSchema, }, ProposedNewState: testEmptyPlan, @@ -4225,10 +4195,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, request: &fwserver.PlanResourceChangeRequest{ Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaTypeComputedRequired, map[string]tftypes.Value{ - "test_computed": tftypes.NewValue(tftypes.String, nil), - "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), - }), + Raw: tftypes.NewValue(testSchemaTypeComputedRequired, nil), Schema: testSchemaAttributePlanModifierPrivatePlanResponse, }, ProposedNewState: testEmptyPlan, @@ -4337,1630 +4304,1630 @@ func TestServerPlanResourceChange(t *testing.T) { PlannedPrivate: testEmptyPrivate, }, }, - "update-set-default-values": { - server: &fwserver.Server{ - Provider: &testprovider.Provider{}, - }, - request: &fwserver.PlanResourceChangeRequest{ - Config: &tfsdk.Config{ - Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ - "test_computed_bool": tftypes.NewValue(tftypes.Bool, nil), - "test_computed_float32": tftypes.NewValue(tftypes.Number, nil), - "test_computed_float64": tftypes.NewValue(tftypes.Number, nil), - "test_computed_int32": tftypes.NewValue(tftypes.Number, nil), - "test_computed_int64": tftypes.NewValue(tftypes.Number, nil), - "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), - "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), - "test_computed_number": tftypes.NewValue(tftypes.Number, nil), - "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, nil), - "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), - "test_computed_string": tftypes.NewValue(tftypes.String, nil), - "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, nil), - "test_computed_dynamic": tftypes.NewValue(tftypes.DynamicPseudoType, nil), - "test_computed_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - nil, - ), - "test_computed_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - }, - ), - "test_computed_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - nil, - ), - "test_computed_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - }, - ), - "test_computed_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - nil, - ), - "test_computed_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - }, - ), - "test_computed_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - nil, - ), - "test_computed_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - "test_configured_bool": tftypes.NewValue(tftypes.Bool, true), - "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(float32Value)), - "test_configured_float64": tftypes.NewValue(tftypes.Number, 1.2), - "test_configured_int32": tftypes.NewValue(tftypes.Number, 123), - "test_configured_int64": tftypes.NewValue(tftypes.Number, 123), - "test_configured_list": tftypes.NewValue( - tftypes.List{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_map": tftypes.NewValue( - tftypes.Map{ElementType: tftypes.String}, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_number": tftypes.NewValue(tftypes.Number, 1.2), - "test_configured_object": tftypes.NewValue( - tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, - map[string]tftypes.Value{ - "a": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_set": tftypes.NewValue( - tftypes.Set{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_string": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_dynamic": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }, - ), - "test_configured_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }, - ), - "test_configured_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - // TODO: Prevent random attributes map access from causing flaky test - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // tftypes.NewValue( - // tftypes.Object{ - // AttributeTypes: map[string]tftypes.Type{ - // "computed_attribute": tftypes.String, - // "configurable_attribute": tftypes.String, - // }, - // }, - // map[string]tftypes.Value{ - // "computed_attribute": tftypes.NewValue(tftypes.String, nil), - // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - // }, - // ), - }, - ), - "test_configured_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, nil), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }), - Schema: testSchemaDefault, - }, - ProposedNewState: &tfsdk.Plan{ - Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ - "test_computed_bool": tftypes.NewValue(tftypes.Bool, nil), - "test_computed_float32": tftypes.NewValue(tftypes.Number, nil), - "test_computed_float64": tftypes.NewValue(tftypes.Number, nil), - "test_computed_int32": tftypes.NewValue(tftypes.Number, nil), - "test_computed_int64": tftypes.NewValue(tftypes.Number, nil), - "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), - "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), - "test_computed_number": tftypes.NewValue(tftypes.Number, nil), - "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, nil), - "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), - "test_computed_string": tftypes.NewValue(tftypes.String, nil), - "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, nil), - "test_computed_dynamic": tftypes.NewValue(tftypes.DynamicPseudoType, nil), - "test_computed_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - nil, - ), - "test_computed_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - }, - ), - "test_computed_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - nil, - ), - "test_computed_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - }, - ), - "test_computed_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - nil, - ), - "test_computed_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - }, - ), - "test_computed_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - nil, - ), - "test_computed_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, nil), - }, - ), - "test_configured_bool": tftypes.NewValue(tftypes.Bool, true), - "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(float32Value)), - "test_configured_float64": tftypes.NewValue(tftypes.Number, 1.2), - "test_configured_int64": tftypes.NewValue(tftypes.Number, 123), - "test_configured_int32": tftypes.NewValue(tftypes.Number, 123), - "test_configured_list": tftypes.NewValue( - tftypes.List{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_map": tftypes.NewValue( - tftypes.Map{ElementType: tftypes.String}, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_number": tftypes.NewValue(tftypes.Number, 1.2), - "test_configured_object": tftypes.NewValue( - tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, - map[string]tftypes.Value{ - "a": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_set": tftypes.NewValue( - tftypes.Set{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_string": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_dynamic": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }, - ), - "test_configured_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }, - ), - "test_configured_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - // TODO: Prevent random attributes map access from causing flaky test - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // tftypes.NewValue( - // tftypes.Object{ - // AttributeTypes: map[string]tftypes.Type{ - // "computed_attribute": tftypes.String, - // "configurable_attribute": tftypes.String, - // }, - // }, - // map[string]tftypes.Value{ - // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior - // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - // }, - // ), - }, - ), - "test_configured_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }), - Schema: testSchemaDefault, - }, - PriorState: &tfsdk.State{ - Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ - "test_computed_bool": tftypes.NewValue(tftypes.Bool, false), - "test_computed_float32": tftypes.NewValue(tftypes.Number, float64(updatedFloat32Value)), - "test_computed_float64": tftypes.NewValue(tftypes.Number, 5.4321), - "test_computed_int32": tftypes.NewValue(tftypes.Number, 54321), - "test_computed_int64": tftypes.NewValue(tftypes.Number, 54321), - "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "prior-state")}), - "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "prior-state")}), - "test_computed_number": tftypes.NewValue(tftypes.Number, big.NewFloat(5.4321)), - "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "prior-state")}), - "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "prior-state")}), - "test_computed_string": tftypes.NewValue(tftypes.String, "two"), - "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, "two"), - "test_computed_dynamic": tftypes.NewValue(tftypes.String, "two"), - "test_computed_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), - }, - ), - }, - ), - "test_computed_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), - }, - ), - }, - ), - "test_computed_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), - }, - ), - }, - ), - "test_computed_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), - }, - ), - }, - ), - "test_computed_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), - }, - ), - }, - ), - "test_computed_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), - }, - ), - }, - ), - "test_computed_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), - }, - ), - "test_computed_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), - }, - ), - "test_configured_bool": tftypes.NewValue(tftypes.Bool, false), - "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(configuredFloat32Value)), - "test_configured_float64": tftypes.NewValue(tftypes.Number, 2.4), - "test_configured_int32": tftypes.NewValue(tftypes.Number, 456), - "test_configured_int64": tftypes.NewValue(tftypes.Number, 456), - "test_configured_list": tftypes.NewValue( - tftypes.List{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - "test_configured_map": tftypes.NewValue( - tftypes.Map{ElementType: tftypes.String}, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - "test_configured_number": tftypes.NewValue(tftypes.Number, 2.4), - "test_configured_object": tftypes.NewValue( - tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, - map[string]tftypes.Value{ - "a": tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - "test_configured_set": tftypes.NewValue( - tftypes.Set{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - "test_configured_string": tftypes.NewValue(tftypes.String, "state-value"), - "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "state-value"), - "test_configured_dynamic": tftypes.NewValue(tftypes.String, "state-value"), - "test_configured_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - }, - ), - "test_configured_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - }, - ), - "test_configured_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - }, - ), - // TODO: Prevent random attributes map access from causing flaky test - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // tftypes.NewValue( - // tftypes.Object{ - // AttributeTypes: map[string]tftypes.Type{ - // "computed_attribute": tftypes.String, - // "configurable_attribute": tftypes.String, - // }, - // }, - // map[string]tftypes.Value{ - // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - // }, - // ), - }, - ), - "test_configured_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - "test_configured_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), - }, - ), - }), - Schema: testSchemaDefault, - }, - ResourceSchema: testSchemaDefault, - Resource: &testprovider.Resource{}, - }, - expectedResponse: &fwserver.PlanResourceChangeResponse{ - // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - Diagnostics: diag.Diagnostics{ - diag.NewAttributeErrorDiagnostic( - path.Root("test_configured_nested_set_attribute"), - "Duplicate Set Element", - "This attribute contains duplicate values of: tftypes.Object["+ - "\"computed_attribute\":tftypes.String, "+ - "\"configurable_attribute\":tftypes.String"+ - "]<"+ - "\"computed_attribute\":tftypes.String<\"attribute-default-value\">, "+ - "\"configurable_attribute\":tftypes.String<\"attribute-default-value\">"+ - ">", - ), - }, - PlannedState: &tfsdk.State{ - Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ - "test_computed_bool": tftypes.NewValue(tftypes.Bool, true), - "test_computed_float32": tftypes.NewValue(tftypes.Number, float64(computedFloat32Value)), - "test_computed_float64": tftypes.NewValue(tftypes.Number, 1.2345), - "test_computed_int32": tftypes.NewValue(tftypes.Number, 12345), - "test_computed_int64": tftypes.NewValue(tftypes.Number, 12345), - "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "default")}), - "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "default")}), - "test_computed_number": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), - "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "default")}), - "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "default")}), - "test_computed_string": tftypes.NewValue(tftypes.String, "one"), - "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, "one"), - "test_computed_dynamic": tftypes.NewValue(tftypes.String, "hello world!"), - "test_computed_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default"), - }, - ), - }, - ), - "test_computed_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), - }, - ), - }, - ), - "test_computed_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default"), - }, - ), - }, - ), - "test_computed_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), - }, - ), - }, - ), - "test_computed_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default"), - }, - ), - }, - ), - "test_computed_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), - }, - ), - }, - ), - "test_computed_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default"), - }, - ), - "test_computed_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "string_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), - }, - ), - "test_configured_bool": tftypes.NewValue(tftypes.Bool, true), - "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(float32Value)), - "test_configured_float64": tftypes.NewValue(tftypes.Number, 1.2), - "test_configured_int32": tftypes.NewValue(tftypes.Number, 123), - "test_configured_int64": tftypes.NewValue(tftypes.Number, 123), - "test_configured_list": tftypes.NewValue( - tftypes.List{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_map": tftypes.NewValue( - tftypes.Map{ElementType: tftypes.String}, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_number": tftypes.NewValue(tftypes.Number, 1.2), - "test_configured_object": tftypes.NewValue( - tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, - map[string]tftypes.Value{ - "a": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_set": tftypes.NewValue( - tftypes.Set{ElementType: tftypes.String}, - []tftypes.Value{ - tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_string": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_dynamic": tftypes.NewValue(tftypes.String, "config-value"), - "test_configured_nested_list": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_list_attribute": tftypes.NewValue( - tftypes.List{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - }, - ), - }, - ), - "test_configured_nested_map": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }, - ), - "test_configured_nested_map_attribute": tftypes.NewValue( - tftypes.Map{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - map[string]tftypes.Value{ - "test-key": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }, - ), - "test_configured_nested_set": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - }, - ), - // TODO: Prevent random attributes map access from causing flaky test (also fix above data) - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // tftypes.NewValue( - // tftypes.Object{ - // AttributeTypes: map[string]tftypes.Type{ - // "computed_attribute": tftypes.String, - // "configurable_attribute": tftypes.String, - // }, - // }, - // map[string]tftypes.Value{ - // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - // // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - // "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - // }, - // ), - }, - ), - "test_configured_nested_set_attribute": tftypes.NewValue( - tftypes.Set{ - ElementType: tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - }, - []tftypes.Value{ - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - }, - ), - tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 - // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - }, - ), - }, - ), - "test_configured_nested_single": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - "test_configured_nested_single_attribute": tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "computed_attribute": tftypes.String, - "configurable_attribute": tftypes.String, - }, - }, - map[string]tftypes.Value{ - "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), - "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), - }, - ), - }), - Schema: testSchemaDefault, - }, - PlannedPrivate: testEmptyPrivate, - }, - }, + //"update-set-default-values": { + // server: &fwserver.Server{ + // Provider: &testprovider.Provider{}, + // }, + // request: &fwserver.PlanResourceChangeRequest{ + // Config: &tfsdk.Config{ + // Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ + // "test_computed_bool": tftypes.NewValue(tftypes.Bool, nil), + // "test_computed_float32": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_float64": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_int32": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_int64": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + // "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), + // "test_computed_number": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, nil), + // "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + // "test_computed_string": tftypes.NewValue(tftypes.String, nil), + // "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, nil), + // "test_computed_dynamic": tftypes.NewValue(tftypes.DynamicPseudoType, nil), + // "test_computed_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // nil, + // ), + // "test_computed_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // }, + // ), + // "test_computed_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // nil, + // ), + // "test_computed_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // }, + // ), + // "test_computed_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // nil, + // ), + // "test_computed_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // }, + // ), + // "test_computed_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // nil, + // ), + // "test_computed_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // "test_configured_bool": tftypes.NewValue(tftypes.Bool, true), + // "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(float32Value)), + // "test_configured_float64": tftypes.NewValue(tftypes.Number, 1.2), + // "test_configured_int32": tftypes.NewValue(tftypes.Number, 123), + // "test_configured_int64": tftypes.NewValue(tftypes.Number, 123), + // "test_configured_list": tftypes.NewValue( + // tftypes.List{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_map": tftypes.NewValue( + // tftypes.Map{ElementType: tftypes.String}, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_number": tftypes.NewValue(tftypes.Number, 1.2), + // "test_configured_object": tftypes.NewValue( + // tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, + // map[string]tftypes.Value{ + // "a": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_set": tftypes.NewValue( + // tftypes.Set{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_string": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_dynamic": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // // TODO: Prevent random attributes map access from causing flaky test + // // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // tftypes.NewValue( + // // tftypes.Object{ + // // AttributeTypes: map[string]tftypes.Type{ + // // "computed_attribute": tftypes.String, + // // "configurable_attribute": tftypes.String, + // // }, + // // }, + // // map[string]tftypes.Value{ + // // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // // }, + // // ), + // }, + // ), + // "test_configured_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, nil), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }), + // Schema: testSchemaDefault, + // }, + // ProposedNewState: &tfsdk.Plan{ + // Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ + // "test_computed_bool": tftypes.NewValue(tftypes.Bool, nil), + // "test_computed_float32": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_float64": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_int32": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_int64": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + // "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), + // "test_computed_number": tftypes.NewValue(tftypes.Number, nil), + // "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, nil), + // "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + // "test_computed_string": tftypes.NewValue(tftypes.String, nil), + // "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, nil), + // "test_computed_dynamic": tftypes.NewValue(tftypes.DynamicPseudoType, nil), + // "test_computed_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // nil, + // ), + // "test_computed_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // }, + // ), + // "test_computed_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // nil, + // ), + // "test_computed_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // }, + // ), + // "test_computed_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // nil, + // ), + // "test_computed_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // }, + // ), + // "test_computed_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // nil, + // ), + // "test_computed_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, nil), + // }, + // ), + // "test_configured_bool": tftypes.NewValue(tftypes.Bool, true), + // "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(float32Value)), + // "test_configured_float64": tftypes.NewValue(tftypes.Number, 1.2), + // "test_configured_int64": tftypes.NewValue(tftypes.Number, 123), + // "test_configured_int32": tftypes.NewValue(tftypes.Number, 123), + // "test_configured_list": tftypes.NewValue( + // tftypes.List{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_map": tftypes.NewValue( + // tftypes.Map{ElementType: tftypes.String}, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_number": tftypes.NewValue(tftypes.Number, 1.2), + // "test_configured_object": tftypes.NewValue( + // tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, + // map[string]tftypes.Value{ + // "a": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_set": tftypes.NewValue( + // tftypes.Set{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_string": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_dynamic": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // // TODO: Prevent random attributes map access from causing flaky test + // // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // tftypes.NewValue( + // // tftypes.Object{ + // // AttributeTypes: map[string]tftypes.Type{ + // // "computed_attribute": tftypes.String, + // // "configurable_attribute": tftypes.String, + // // }, + // // }, + // // map[string]tftypes.Value{ + // // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior + // // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // // }, + // // ), + // }, + // ), + // "test_configured_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), // Terraform core behavior + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }), + // Schema: testSchemaDefault, + // }, + // PriorState: &tfsdk.State{ + // Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ + // "test_computed_bool": tftypes.NewValue(tftypes.Bool, false), + // "test_computed_float32": tftypes.NewValue(tftypes.Number, float64(updatedFloat32Value)), + // "test_computed_float64": tftypes.NewValue(tftypes.Number, 5.4321), + // "test_computed_int32": tftypes.NewValue(tftypes.Number, 54321), + // "test_computed_int64": tftypes.NewValue(tftypes.Number, 54321), + // "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "prior-state")}), + // "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "prior-state")}), + // "test_computed_number": tftypes.NewValue(tftypes.Number, big.NewFloat(5.4321)), + // "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "prior-state")}), + // "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "prior-state")}), + // "test_computed_string": tftypes.NewValue(tftypes.String, "two"), + // "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, "two"), + // "test_computed_dynamic": tftypes.NewValue(tftypes.String, "two"), + // "test_computed_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), + // }, + // ), + // }, + // ), + // "test_computed_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), + // }, + // ), + // }, + // ), + // "test_computed_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), + // }, + // ), + // }, + // ), + // "test_computed_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), + // }, + // ), + // }, + // ), + // "test_computed_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), + // }, + // ), + // }, + // ), + // "test_computed_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), + // }, + // ), + // }, + // ), + // "test_computed_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state"), + // }, + // ), + // "test_computed_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "prior-state-attribute"), + // }, + // ), + // "test_configured_bool": tftypes.NewValue(tftypes.Bool, false), + // "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(configuredFloat32Value)), + // "test_configured_float64": tftypes.NewValue(tftypes.Number, 2.4), + // "test_configured_int32": tftypes.NewValue(tftypes.Number, 456), + // "test_configured_int64": tftypes.NewValue(tftypes.Number, 456), + // "test_configured_list": tftypes.NewValue( + // tftypes.List{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // "test_configured_map": tftypes.NewValue( + // tftypes.Map{ElementType: tftypes.String}, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // "test_configured_number": tftypes.NewValue(tftypes.Number, 2.4), + // "test_configured_object": tftypes.NewValue( + // tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, + // map[string]tftypes.Value{ + // "a": tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // "test_configured_set": tftypes.NewValue( + // tftypes.Set{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // "test_configured_string": tftypes.NewValue(tftypes.String, "state-value"), + // "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "state-value"), + // "test_configured_dynamic": tftypes.NewValue(tftypes.String, "state-value"), + // "test_configured_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // }, + // ), + // // TODO: Prevent random attributes map access from causing flaky test + // // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // tftypes.NewValue( + // // tftypes.Object{ + // // AttributeTypes: map[string]tftypes.Type{ + // // "computed_attribute": tftypes.String, + // // "configurable_attribute": tftypes.String, + // // }, + // // }, + // // map[string]tftypes.Value{ + // // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // // }, + // // ), + // }, + // ), + // "test_configured_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // "test_configured_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "state-value"), + // }, + // ), + // }), + // Schema: testSchemaDefault, + // }, + // ResourceSchema: testSchemaDefault, + // Resource: &testprovider.Resource{}, + // }, + // expectedResponse: &fwserver.PlanResourceChangeResponse{ + // // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // Diagnostics: diag.Diagnostics{ + // diag.NewAttributeErrorDiagnostic( + // path.Root("test_configured_nested_set_attribute"), + // "Duplicate Set Element", + // "This attribute contains duplicate values of: tftypes.Object["+ + // "\"computed_attribute\":tftypes.String, "+ + // "\"configurable_attribute\":tftypes.String"+ + // "]<"+ + // "\"computed_attribute\":tftypes.String<\"attribute-default-value\">, "+ + // "\"configurable_attribute\":tftypes.String<\"attribute-default-value\">"+ + // ">", + // ), + // }, + // PlannedState: &tfsdk.State{ + // Raw: tftypes.NewValue(testSchemaTypeDefault, map[string]tftypes.Value{ + // "test_computed_bool": tftypes.NewValue(tftypes.Bool, true), + // "test_computed_float32": tftypes.NewValue(tftypes.Number, float64(computedFloat32Value)), + // "test_computed_float64": tftypes.NewValue(tftypes.Number, 1.2345), + // "test_computed_int32": tftypes.NewValue(tftypes.Number, 12345), + // "test_computed_int64": tftypes.NewValue(tftypes.Number, 12345), + // "test_computed_list": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "default")}), + // "test_computed_map": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "default")}), + // "test_computed_number": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + // "test_computed_object": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, map[string]tftypes.Value{"a": tftypes.NewValue(tftypes.String, "default")}), + // "test_computed_set": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{tftypes.NewValue(tftypes.String, "default")}), + // "test_computed_string": tftypes.NewValue(tftypes.String, "one"), + // "test_computed_string_custom_type": tftypes.NewValue(tftypes.String, "one"), + // "test_computed_dynamic": tftypes.NewValue(tftypes.String, "hello world!"), + // "test_computed_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default"), + // }, + // ), + // }, + // ), + // "test_computed_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), + // }, + // ), + // }, + // ), + // "test_computed_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default"), + // }, + // ), + // }, + // ), + // "test_computed_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), + // }, + // ), + // }, + // ), + // "test_computed_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default"), + // }, + // ), + // }, + // ), + // "test_computed_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), + // }, + // ), + // }, + // ), + // "test_computed_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default"), + // }, + // ), + // "test_computed_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "string_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "string_attribute": tftypes.NewValue(tftypes.String, "default-attribute"), + // }, + // ), + // "test_configured_bool": tftypes.NewValue(tftypes.Bool, true), + // "test_configured_float32": tftypes.NewValue(tftypes.Number, float64(float32Value)), + // "test_configured_float64": tftypes.NewValue(tftypes.Number, 1.2), + // "test_configured_int32": tftypes.NewValue(tftypes.Number, 123), + // "test_configured_int64": tftypes.NewValue(tftypes.Number, 123), + // "test_configured_list": tftypes.NewValue( + // tftypes.List{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_map": tftypes.NewValue( + // tftypes.Map{ElementType: tftypes.String}, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_number": tftypes.NewValue(tftypes.Number, 1.2), + // "test_configured_object": tftypes.NewValue( + // tftypes.Object{AttributeTypes: map[string]tftypes.Type{"a": tftypes.String}}, + // map[string]tftypes.Value{ + // "a": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_set": tftypes.NewValue( + // tftypes.Set{ElementType: tftypes.String}, + // []tftypes.Value{ + // tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_string": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_string_custom_type": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_dynamic": tftypes.NewValue(tftypes.String, "config-value"), + // "test_configured_nested_list": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_list_attribute": tftypes.NewValue( + // tftypes.List{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_map_attribute": tftypes.NewValue( + // tftypes.Map{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // map[string]tftypes.Value{ + // "test-key": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_set": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // }, + // ), + // // TODO: Prevent random attributes map access from causing flaky test (also fix above data) + // // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // tftypes.NewValue( + // // tftypes.Object{ + // // AttributeTypes: map[string]tftypes.Type{ + // // "computed_attribute": tftypes.String, + // // "configurable_attribute": tftypes.String, + // // }, + // // }, + // // map[string]tftypes.Value{ + // // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // // // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // // "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // // }, + // // ), + // }, + // ), + // "test_configured_nested_set_attribute": tftypes.NewValue( + // tftypes.Set{ + // ElementType: tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // }, + // []tftypes.Value{ + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-1"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // }, + // ), + // tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // // TODO: https://github.com/hashicorp/terraform-plugin-framework/issues/783 + // // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value-element-2"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // }, + // ), + // }, + // ), + // "test_configured_nested_single": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // "test_configured_nested_single_attribute": tftypes.NewValue( + // tftypes.Object{ + // AttributeTypes: map[string]tftypes.Type{ + // "computed_attribute": tftypes.String, + // "configurable_attribute": tftypes.String, + // }, + // }, + // map[string]tftypes.Value{ + // "computed_attribute": tftypes.NewValue(tftypes.String, "attribute-default-value"), + // "configurable_attribute": tftypes.NewValue(tftypes.String, "config-value"), + // }, + // ), + // }), + // Schema: testSchemaDefault, + // }, + // PlannedPrivate: testEmptyPrivate, + // }, + //}, "update-attributeplanmodifier-request-private": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, diff --git a/internal/testing/testschema/schema.go b/internal/testing/testschema/schema.go index db91aa9cd..7d6e57fb0 100644 --- a/internal/testing/testschema/schema.go +++ b/internal/testing/testschema/schema.go @@ -24,6 +24,10 @@ type Schema struct { Version int64 } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep satisfies the fwschema.Schema interface. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { return fwschema.SchemaApplyTerraform5AttributePathStep(s, step) diff --git a/list/schema/schema.go b/list/schema/schema.go index 456cfc428..46115a9d8 100644 --- a/list/schema/schema.go +++ b/list/schema/schema.go @@ -60,6 +60,10 @@ type Schema struct { DeprecationMessage string } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { diff --git a/provider/metaschema/schema.go b/provider/metaschema/schema.go index b43826456..a7b1ed729 100644 --- a/provider/metaschema/schema.go +++ b/provider/metaschema/schema.go @@ -30,6 +30,10 @@ type Schema struct { Attributes map[string]Attribute } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { diff --git a/provider/schema/schema.go b/provider/schema/schema.go index 91cb1781f..318c467c7 100644 --- a/provider/schema/schema.go +++ b/provider/schema/schema.go @@ -59,6 +59,10 @@ type Schema struct { DeprecationMessage string } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { diff --git a/resource/identityschema/schema.go b/resource/identityschema/schema.go index 6d68aff9a..8d77269c4 100644 --- a/resource/identityschema/schema.go +++ b/resource/identityschema/schema.go @@ -37,6 +37,10 @@ type Schema struct { Version int64 } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) { diff --git a/resource/schema/schema.go b/resource/schema/schema.go index 0f280662f..c369a826d 100644 --- a/resource/schema/schema.go +++ b/resource/schema/schema.go @@ -72,6 +72,10 @@ type Schema struct { Version int64 } +func (s Schema) EmptyValue(ctx context.Context) tftypes.Value { + return fwschema.EmptySchemaValue(ctx, s) +} + // ApplyTerraform5AttributePathStep applies the given AttributePathStep to the // schema. func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (any, error) {