diff --git a/tfsdk/config.go b/tfsdk/config.go index 57451584b..30fd343b1 100644 --- a/tfsdk/config.go +++ b/tfsdk/config.go @@ -90,7 +90,6 @@ func (c Config) getAttributeValue(ctx context.Context, path *tftypes.AttributePa // TODO: If ErrInvalidStep, check parent paths for unknown value. // If found, convert this value to an unknown value. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186 - if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok { diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path)...) diff --git a/tfsdk/config_test.go b/tfsdk/config_test.go index 5401f9f47..c8327b3b7 100644 --- a/tfsdk/config_test.go +++ b/tfsdk/config_test.go @@ -335,6 +335,28 @@ func TestConfigGetAttribute(t *testing.T) { expected: &testtypes.String{String: types.String{Value: "namevalue"}, CreatedBy: testtypes.StringTypeWithValidateWarning{}}, expectedDiags: diag.Diagnostics{testtypes.TestWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("name"))}, }, + "Computed-Computed-object": { + config: Config{ + Raw: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + }, + }, map[string]tftypes.Value{ + "name": tftypes.NewValue(tftypes.String, "namevalue"), + }), + Schema: Schema{ + Attributes: map[string]Attribute{ + "name": { + Type: testtypes.StringTypeWithValidateWarning{}, + Required: true, + }, + }, + }, + }, + target: new(testtypes.String), + expected: &testtypes.String{String: types.String{Value: "namevalue"}, CreatedBy: testtypes.StringTypeWithValidateWarning{}}, + expectedDiags: diag.Diagnostics{testtypes.TestWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("name"))}, + }, } for name, tc := range testCases { @@ -1585,6 +1607,35 @@ func TestConfigGetAttributeValue(t *testing.T) { expected: testtypes.String{String: types.String{Value: "value"}, CreatedBy: testtypes.StringTypeWithValidateWarning{}}, expectedDiags: diag.Diagnostics{testtypes.TestWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"))}, }, + "AttrTypeInt64WithValidateError-nested-missing-in-config": { + config: Config{ + Raw: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "parent": tftypes.Object{}, + }, + }, map[string]tftypes.Value{ + "parent": tftypes.NewValue(tftypes.Object{}, nil), + }), + Schema: Schema{ + Attributes: map[string]Attribute{ + "parent": { + Attributes: SingleNestedAttributes(map[string]Attribute{ + "test": { + Type: types.Int64Type, + Optional: true, + Computed: true, + }, + }), + Computed: true, + Optional: true, + }, + }, + }, + }, + path: tftypes.NewAttributePath().WithAttributeName("parent").WithAttributeName("test"), + expected: types.Int64{Null: true}, + expectedDiags: nil, + }, } for name, tc := range testCases { diff --git a/tfsdk/state.go b/tfsdk/state.go index d0340975b..d28b00030 100644 --- a/tfsdk/state.go +++ b/tfsdk/state.go @@ -91,11 +91,13 @@ func (s State) getAttributeValue(ctx context.Context, path *tftypes.AttributePat // If found, convert this value to an unknown value. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186 - if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok { - diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path)...) + if err == nil { + if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok { + diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path)...) - if diags.HasError() { - return nil, diags + if diags.HasError() { + return nil, diags + } } } diff --git a/tfsdk/state_test.go b/tfsdk/state_test.go index 6014e521b..e7aa42b2a 100644 --- a/tfsdk/state_test.go +++ b/tfsdk/state_test.go @@ -2282,6 +2282,35 @@ func TestStateGetAttributeValue(t *testing.T) { expected: testtypes.String{String: types.String{Value: "value"}, CreatedBy: testtypes.StringTypeWithValidateWarning{}}, expectedDiags: diag.Diagnostics{testtypes.TestWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"))}, }, + "AttrTypeInt64WithValidateError-nested-missing-in-config": { + state: State{ + Raw: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "parent": tftypes.Object{}, + }, + }, map[string]tftypes.Value{ + "parent": tftypes.NewValue(tftypes.Object{}, nil), + }), + Schema: Schema{ + Attributes: map[string]Attribute{ + "parent": { + Attributes: SingleNestedAttributes(map[string]Attribute{ + "test": { + Type: types.Int64Type, + Optional: true, + Computed: true, + }, + }), + Computed: true, + Optional: true, + }, + }, + }, + }, + path: tftypes.NewAttributePath().WithAttributeName("parent").WithAttributeName("test"), + expected: types.Int64{Null: true}, + expectedDiags: nil, + }, } for name, tc := range testCases { diff --git a/types/float64.go b/types/float64.go index 86ca03a94..6783d5db7 100644 --- a/types/float64.go +++ b/types/float64.go @@ -13,6 +13,10 @@ import ( func float64Validate(_ context.Context, in tftypes.Value, path *tftypes.AttributePath) diag.Diagnostics { var diags diag.Diagnostics + if !in.IsKnown() || in.IsNull() { + return diags + } + if !in.Type().Equal(tftypes.Number) { diags.AddAttributeError( path, @@ -23,10 +27,6 @@ func float64Validate(_ context.Context, in tftypes.Value, path *tftypes.Attribut return diags } - if !in.IsKnown() || in.IsNull() { - return diags - } - var value *big.Float err := in.As(&value) diff --git a/types/int64.go b/types/int64.go index 49f491699..82b827cf8 100644 --- a/types/int64.go +++ b/types/int64.go @@ -13,6 +13,10 @@ import ( func int64Validate(_ context.Context, in tftypes.Value, path *tftypes.AttributePath) diag.Diagnostics { var diags diag.Diagnostics + if !in.IsKnown() || in.IsNull() { + return diags + } + if !in.Type().Equal(tftypes.Number) { diags.AddAttributeError( path, @@ -23,10 +27,6 @@ func int64Validate(_ context.Context, in tftypes.Value, path *tftypes.AttributeP return diags } - if !in.IsKnown() || in.IsNull() { - return diags - } - var value *big.Float err := in.As(&value)