diff --git a/.changes/unreleased/BUG FIXES-20230616-140718.yaml b/.changes/unreleased/BUG FIXES-20230616-140718.yaml new file mode 100644 index 000000000..c5889da0c --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20230616-140718.yaml @@ -0,0 +1,6 @@ +kind: BUG FIXES +body: 'resource/schema: Ensured `Default` implementations received request `Path` + and have response `Diagnostics` handled' +time: 2023-06-16T14:07:18.774874-04:00 +custom: + Issue: "778" diff --git a/.changes/unreleased/BUG FIXES-20230616-140834.yaml b/.changes/unreleased/BUG FIXES-20230616-140834.yaml new file mode 100644 index 000000000..7ed5d5428 --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20230616-140834.yaml @@ -0,0 +1,6 @@ +kind: BUG FIXES +body: 'resource/schema: Prevented panics with `Default` implementations on list, map, + and set where no response `Diagnostics` or `PlanValue` was returned' +time: 2023-06-16T14:08:34.806147-04:00 +custom: + Issue: "778" diff --git a/internal/fwschemadata/data_default.go b/internal/fwschemadata/data_default.go index 5b48c2f39..a69845c48 100644 --- a/internal/fwschemadata/data_default.go +++ b/internal/fwschemadata/data_default.go @@ -75,76 +75,229 @@ func (d *Data) TransformDefaults(ctx context.Context, configRaw tftypes.Value) d switch a := attrAtPath.(type) { case fwschema.AttributeWithBoolDefaultValue: defaultValue := a.BoolDefaultValue() - if defaultValue != nil { - resp := defaults.BoolResponse{} - defaultValue.DefaultBool(ctx, defaults.BoolRequest{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil + } + + req := defaults.BoolRequest{ + Path: fwPath, + } + resp := defaults.BoolResponse{} + + defaultValue.DefaultBool(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) case fwschema.AttributeWithFloat64DefaultValue: defaultValue := a.Float64DefaultValue() - if defaultValue != nil { - resp := defaults.Float64Response{} - defaultValue.DefaultFloat64(ctx, defaults.Float64Request{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil + } + + req := defaults.Float64Request{ + Path: fwPath, } + resp := defaults.Float64Response{} + + defaultValue.DefaultFloat64(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil + } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) case fwschema.AttributeWithInt64DefaultValue: defaultValue := a.Int64DefaultValue() - if defaultValue != nil { - resp := defaults.Int64Response{} - defaultValue.DefaultInt64(ctx, defaults.Int64Request{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil + } + + req := defaults.Int64Request{ + Path: fwPath, + } + resp := defaults.Int64Response{} + + defaultValue.DefaultInt64(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) + case fwschema.AttributeWithListDefaultValue: defaultValue := a.ListDefaultValue() - if defaultValue != nil { - resp := defaults.ListResponse{} - defaultValue.DefaultList(ctx, defaults.ListRequest{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil + } + + req := defaults.ListRequest{ + Path: fwPath, + } + resp := defaults.ListResponse{} + + defaultValue.DefaultList(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil } + + if resp.PlanValue.ElementType(ctx) == nil { + logging.FrameworkWarn(ctx, "attribute default declared, but returned no value") + + return tfTypeValue, nil + } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) case fwschema.AttributeWithMapDefaultValue: defaultValue := a.MapDefaultValue() - if defaultValue != nil { - resp := defaults.MapResponse{} - defaultValue.DefaultMap(ctx, defaults.MapRequest{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil } + req := defaults.MapRequest{ + Path: fwPath, + } + resp := defaults.MapResponse{} + + defaultValue.DefaultMap(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil + } + + if resp.PlanValue.ElementType(ctx) == nil { + logging.FrameworkWarn(ctx, "attribute default declared, but returned no value") + + return tfTypeValue, nil + } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) case fwschema.AttributeWithNumberDefaultValue: defaultValue := a.NumberDefaultValue() - if defaultValue != nil { - resp := defaults.NumberResponse{} - defaultValue.DefaultNumber(ctx, defaults.NumberRequest{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil + } + + req := defaults.NumberRequest{ + Path: fwPath, + } + resp := defaults.NumberResponse{} + + defaultValue.DefaultNumber(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) case fwschema.AttributeWithObjectDefaultValue: defaultValue := a.ObjectDefaultValue() - if defaultValue != nil { - resp := defaults.ObjectResponse{} - defaultValue.DefaultObject(ctx, defaults.ObjectRequest{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil + } + + req := defaults.ObjectRequest{ + Path: fwPath, } + resp := defaults.ObjectResponse{} + + defaultValue.DefaultObject(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil + } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) case fwschema.AttributeWithSetDefaultValue: defaultValue := a.SetDefaultValue() - if defaultValue != nil { - resp := defaults.SetResponse{} - defaultValue.DefaultSet(ctx, defaults.SetRequest{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil + } + + req := defaults.SetRequest{ + Path: fwPath, + } + resp := defaults.SetResponse{} + + defaultValue.DefaultSet(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil + } + + if resp.PlanValue.ElementType(ctx) == nil { + logging.FrameworkWarn(ctx, "attribute default declared, but returned no value") + + return tfTypeValue, nil } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) case fwschema.AttributeWithStringDefaultValue: defaultValue := a.StringDefaultValue() - if defaultValue != nil { - resp := defaults.StringResponse{} - defaultValue.DefaultString(ctx, defaults.StringRequest{}, &resp) - logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) - return resp.PlanValue.ToTerraformValue(ctx) + + if defaultValue == nil { + return tfTypeValue, nil } + + req := defaults.StringRequest{ + Path: fwPath, + } + resp := defaults.StringResponse{} + + defaultValue.DefaultString(ctx, req, &resp) + + diags.Append(resp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return tfTypeValue, nil + } + + logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath, resp.PlanValue)) + + return resp.PlanValue.ToTerraformValue(ctx) } return tfTypeValue, nil diff --git a/internal/fwschemadata/data_default_test.go b/internal/fwschemadata/data_default_test.go index d6b9fa545..1bcdb5c3e 100644 --- a/internal/fwschemadata/data_default_test.go +++ b/internal/fwschemadata/data_default_test.go @@ -5,6 +5,7 @@ package fwschemadata_test import ( "context" + "fmt" "math/big" "testing" @@ -15,9 +16,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testdefaults" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testschema" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" "github.com/hashicorp/terraform-plugin-framework/resource/schema/float64default" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault" @@ -38,6 +42,148 @@ func TestDataDefault(t *testing.T) { expected *fwschemadata.Data expectedDiags diag.Diagnostics }{ + "bool-attribute-request-path": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "bool_attribute": testschema.AttributeWithBoolDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Bool{ + DefaultBoolMethod: func(ctx context.Context, req defaults.BoolRequest, resp *defaults.BoolResponse) { + if !req.Path.Equal(path.Root("bool_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("bool_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "bool_attribute": tftypes.Bool, + }, + }, + map[string]tftypes.Value{ + "bool_attribute": tftypes.NewValue(tftypes.Bool, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "bool_attribute": tftypes.Bool, + }, + }, + map[string]tftypes.Value{ + "bool_attribute": tftypes.NewValue(tftypes.Bool, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "bool_attribute": testschema.AttributeWithBoolDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Bool{ + DefaultBoolMethod: func(ctx context.Context, req defaults.BoolRequest, resp *defaults.BoolResponse) { + if !req.Path.Equal(path.Root("bool_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("bool_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "bool_attribute": tftypes.Bool, + }, + }, + map[string]tftypes.Value{ + "bool_attribute": tftypes.NewValue(tftypes.Bool, nil), + }, + ), + }, + }, + "bool-attribute-response-diagnostics": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "bool_attribute": testschema.AttributeWithBoolDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Bool{ + DefaultBoolMethod: func(ctx context.Context, req defaults.BoolRequest, resp *defaults.BoolResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "bool_attribute": tftypes.Bool, + }, + }, + map[string]tftypes.Value{ + "bool_attribute": tftypes.NewValue(tftypes.Bool, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "bool_attribute": tftypes.Bool, + }, + }, + map[string]tftypes.Value{ + "bool_attribute": tftypes.NewValue(tftypes.Bool, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "bool_attribute": testschema.AttributeWithBoolDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Bool{ + DefaultBoolMethod: func(ctx context.Context, req defaults.BoolRequest, resp *defaults.BoolResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "bool_attribute": tftypes.Bool, + }, + }, + map[string]tftypes.Value{ + "bool_attribute": tftypes.NewValue(tftypes.Bool, nil), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, + }, "bool-attribute-not-null-unmodified-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, @@ -250,6 +396,148 @@ func TestDataDefault(t *testing.T) { ), }, }, + "float64-attribute-request-path": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "float64_attribute": testschema.AttributeWithFloat64DefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Float64{ + DefaultFloat64Method: func(ctx context.Context, req defaults.Float64Request, resp *defaults.Float64Response) { + if !req.Path.Equal(path.Root("float64_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("float64_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "float64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "float64_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "float64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "float64_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "float64_attribute": testschema.AttributeWithFloat64DefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Float64{ + DefaultFloat64Method: func(ctx context.Context, req defaults.Float64Request, resp *defaults.Float64Response) { + if !req.Path.Equal(path.Root("float64_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("float64_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "float64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "float64_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + }, + "float64-attribute-response-diagnostics": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "float64_attribute": testschema.AttributeWithFloat64DefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Float64{ + DefaultFloat64Method: func(ctx context.Context, req defaults.Float64Request, resp *defaults.Float64Response) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "float64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "float64_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "float64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "float64_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "float64_attribute": testschema.AttributeWithFloat64DefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Float64{ + DefaultFloat64Method: func(ctx context.Context, req defaults.Float64Request, resp *defaults.Float64Response) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "float64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "float64_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, + }, "float64-attribute-not-null-unmodified-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, @@ -462,14 +750,24 @@ func TestDataDefault(t *testing.T) { ), }, }, - "int64-attribute-not-null-unmodified-default": { + "int64-attribute-request-path": { data: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Optional: true, Computed: true, - Default: int64default.StaticInt64(54321), + Default: testdefaults.Int64{ + DefaultInt64Method: func(ctx context.Context, req defaults.Int64Request, resp *defaults.Int64Response) { + if !req.Path.Equal(path.Root("int64_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("int64_attribute"), req.Path), + ) + } + }, + }, }, }, }, @@ -480,7 +778,7 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), }, ), }, @@ -490,16 +788,26 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, 54321), // value in rawConfig + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), }, ), expected: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Optional: true, Computed: true, - Default: int64default.StaticInt64(54321), + Default: testdefaults.Int64{ + DefaultInt64Method: func(ctx context.Context, req defaults.Int64Request, resp *defaults.Int64Response) { + if !req.Path.Equal(path.Root("int64_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("int64_attribute"), req.Path), + ) + } + }, + }, }, }, }, @@ -510,19 +818,25 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), }, ), }, }, - "int64-attribute-null-unmodified-no-default": { + "int64-attribute-response-diagnostics": { data: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "int64_attribute": testschema.Attribute{ + "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Optional: true, Computed: true, - Type: types.Int64Type, + Default: testdefaults.Int64{ + DefaultInt64Method: func(ctx context.Context, req defaults.Int64Request, resp *defaults.Int64Response) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, }, }, }, @@ -533,7 +847,7 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), }, ), }, @@ -543,16 +857,22 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), }, ), expected: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "int64_attribute": testschema.Attribute{ + "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Optional: true, Computed: true, - Type: types.Int64Type, + Default: testdefaults.Int64{ + DefaultInt64Method: func(ctx context.Context, req defaults.Int64Request, resp *defaults.Int64Response) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, }, }, }, @@ -563,12 +883,16 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), }, ), }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, }, - "int64-attribute-null-modified-default": { + "int64-attribute-not-null-unmodified-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, Schema: testschema.Schema{ @@ -596,7 +920,7 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig + "int64_attribute": tftypes.NewValue(tftypes.Number, 54321), // value in rawConfig }, ), expected: &fwschemadata.Data{ @@ -616,19 +940,19 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "int64_attribute": tftypes.NewValue(tftypes.Number, 54321), + "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), }, ), }, }, - "int64-attribute-null-unmodified-default-nil": { + "int64-attribute-null-unmodified-no-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + "int64_attribute": testschema.Attribute{ Computed: true, - Default: nil, + Type: types.Int64Type, }, }, }, @@ -656,9 +980,9 @@ func TestDataDefault(t *testing.T) { Description: fwschemadata.DataDescriptionState, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + "int64_attribute": testschema.Attribute{ Computed: true, - Default: nil, + Type: types.Int64Type, }, }, }, @@ -674,22 +998,274 @@ func TestDataDefault(t *testing.T) { ), }, }, - "list-attribute-not-null-unmodified-default": { + "int64-attribute-null-modified-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "list_attribute": testschema.AttributeWithListDefaultValue{ - Optional: true, - ElementType: types.StringType, - Default: listdefault.StaticValue( - types.ListValueMust( - types.StringType, - []attr.Value{ - types.StringValue("two"), - }, - ), - ), + "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Computed: true, + Default: int64default.StaticInt64(54321), + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "int64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "int64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Computed: true, + Default: int64default.StaticInt64(54321), + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "int64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "int64_attribute": tftypes.NewValue(tftypes.Number, 54321), + }, + ), + }, + }, + "int64-attribute-null-unmodified-default-nil": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Computed: true, + Default: nil, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "int64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "int64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "int64_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "int64_attribute": testschema.AttributeWithInt64DefaultValue{ + Computed: true, + Default: nil, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "int64_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "int64_attribute": tftypes.NewValue(tftypes.Number, 12345), + }, + ), + }, + }, + "list-attribute-request-path": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "list_attribute": testschema.AttributeWithListDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.List{ + DefaultListMethod: func(ctx context.Context, req defaults.ListRequest, resp *defaults.ListResponse) { + if !req.Path.Equal(path.Root("list_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("list_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "list_attribute": testschema.AttributeWithListDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.List{ + DefaultListMethod: func(ctx context.Context, req defaults.ListRequest, resp *defaults.ListResponse) { + if !req.Path.Equal(path.Root("list_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("list_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + }, + ), + }, + }, + "list-attribute-response-diagnostics": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "list_attribute": testschema.AttributeWithListDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.List{ + DefaultListMethod: func(ctx context.Context, req defaults.ListRequest, resp *defaults.ListResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "list_attribute": testschema.AttributeWithListDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.List{ + DefaultListMethod: func(ctx context.Context, req defaults.ListRequest, resp *defaults.ListResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, nil), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, + }, + "list-attribute-not-null-unmodified-default": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "list_attribute": testschema.AttributeWithListDefaultValue{ + Optional: true, + ElementType: types.StringType, + Default: listdefault.StaticValue( + types.ListValueMust( + types.StringType, + []attr.Value{ + types.StringValue("two"), + }, + ), + ), }, }, }, @@ -905,93 +1481,239 @@ func TestDataDefault(t *testing.T) { TerraformValue: tftypes.NewValue( tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "list_attribute": tftypes.List{ - ElementType: tftypes.String, - }, + "list_attribute": tftypes.List{ + ElementType: tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.String, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.String, "two"), + }), + }, + ), + }, + }, + "list-attribute-null-unmodified-default-nil": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "list_attribute": testschema.AttributeWithListDefaultValue{ + Optional: true, + ElementType: types.StringType, + Default: nil, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ + ElementType: tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.String, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.String, "one"), + }), + }, + ), + }, + rawConfig: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ + ElementType: tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.String, + }, nil, + ), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "list_attribute": testschema.AttributeWithListDefaultValue{ + Optional: true, + ElementType: types.StringType, + Default: nil, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "list_attribute": tftypes.List{ + ElementType: tftypes.String, + }, + }, + }, + map[string]tftypes.Value{ + "list_attribute": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.String, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.String, "one"), + }), + }, + ), + }, + }, + "map-attribute-request-path": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "map_attribute": testschema.AttributeWithMapDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.Map{ + DefaultMapMethod: func(ctx context.Context, req defaults.MapRequest, resp *defaults.MapResponse) { + if !req.Path.Equal(path.Root("map_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("map_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "map_attribute": tftypes.Map{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "map_attribute": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "map_attribute": tftypes.Map{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "map_attribute": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "map_attribute": testschema.AttributeWithMapDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.Map{ + DefaultMapMethod: func(ctx context.Context, req defaults.MapRequest, resp *defaults.MapResponse) { + if !req.Path.Equal(path.Root("map_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("map_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "map_attribute": tftypes.Map{ElementType: tftypes.String}, }, }, map[string]tftypes.Value{ - "list_attribute": tftypes.NewValue(tftypes.List{ - ElementType: tftypes.String, - }, []tftypes.Value{ - tftypes.NewValue(tftypes.String, "two"), - }), + "map_attribute": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), }, ), }, }, - "list-attribute-null-unmodified-default-nil": { + "map-attribute-response-diagnostics": { data: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "list_attribute": testschema.AttributeWithListDefaultValue{ + "map_attribute": testschema.AttributeWithMapDefaultValue{ Optional: true, + Computed: true, ElementType: types.StringType, - Default: nil, + Default: testdefaults.Map{ + DefaultMapMethod: func(ctx context.Context, req defaults.MapRequest, resp *defaults.MapResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, }, }, }, TerraformValue: tftypes.NewValue( tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "list_attribute": tftypes.List{ - ElementType: tftypes.String, - }, + "map_attribute": tftypes.Map{ElementType: tftypes.String}, }, }, map[string]tftypes.Value{ - "list_attribute": tftypes.NewValue(tftypes.List{ - ElementType: tftypes.String, - }, []tftypes.Value{ - tftypes.NewValue(tftypes.String, "one"), - }), + "map_attribute": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), }, ), }, - rawConfig: tftypes.NewValue( - tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "list_attribute": tftypes.List{ - ElementType: tftypes.String, - }, - }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "map_attribute": tftypes.Map{ElementType: tftypes.String}, }, + }, map[string]tftypes.Value{ - "list_attribute": tftypes.NewValue(tftypes.List{ - ElementType: tftypes.String, - }, nil, - ), + "map_attribute": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), }, ), expected: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "list_attribute": testschema.AttributeWithListDefaultValue{ + "map_attribute": testschema.AttributeWithMapDefaultValue{ Optional: true, + Computed: true, ElementType: types.StringType, - Default: nil, + Default: testdefaults.Map{ + DefaultMapMethod: func(ctx context.Context, req defaults.MapRequest, resp *defaults.MapResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, }, }, }, TerraformValue: tftypes.NewValue( tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "list_attribute": tftypes.List{ - ElementType: tftypes.String, - }, + "map_attribute": tftypes.Map{ElementType: tftypes.String}, }, }, map[string]tftypes.Value{ - "list_attribute": tftypes.NewValue(tftypes.List{ - ElementType: tftypes.String, - }, []tftypes.Value{ - tftypes.NewValue(tftypes.String, "one"), - }), + "map_attribute": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil), }, ), }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, }, "map-attribute-not-null-unmodified-default": { data: &fwschemadata.Data{ @@ -1312,7 +2034,255 @@ func TestDataDefault(t *testing.T) { ), }, }, - "number-attribute-not-null-unmodified-default": { + "number-attribute-request-path": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Number{ + DefaultNumberMethod: func(ctx context.Context, req defaults.NumberRequest, resp *defaults.NumberResponse) { + if !req.Path.Equal(path.Root("number_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("number_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Number{ + DefaultNumberMethod: func(ctx context.Context, req defaults.NumberRequest, resp *defaults.NumberResponse) { + if !req.Path.Equal(path.Root("number_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("number_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + }, + "number-attribute-response-diagnostics": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Number{ + DefaultNumberMethod: func(ctx context.Context, req defaults.NumberRequest, resp *defaults.NumberResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.Number{ + DefaultNumberMethod: func(ctx context.Context, req defaults.NumberRequest, resp *defaults.NumberResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, nil), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, + }, + "number-attribute-not-null-unmodified-default": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ + Computed: true, + Default: numberdefault.StaticBigFloat(big.NewFloat(5.4321)), + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(5.4321)), // value in rawConfig + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ + Computed: true, + Default: numberdefault.StaticBigFloat(big.NewFloat(5.4321)), + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + }, + ), + }, + }, + "number-attribute-null-unmodified-no-default": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.Attribute{ + Computed: true, + Type: types.NumberType, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionState, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "number_attribute": testschema.Attribute{ + Computed: true, + Type: types.NumberType, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "number_attribute": tftypes.Number, + }, + }, + map[string]tftypes.Value{ + "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + }, + ), + }, + }, + "number-attribute-null-modified-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, Schema: testschema.Schema{ @@ -1340,7 +2310,7 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(5.4321)), // value in rawConfig + "number_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig }, ), expected: &fwschemadata.Data{ @@ -1360,19 +2330,19 @@ func TestDataDefault(t *testing.T) { }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(5.4321)), }, ), }, }, - "number-attribute-null-unmodified-no-default": { + "number-attribute-null-unmodified-default-nil": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "number_attribute": testschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ Computed: true, - Type: types.NumberType, + Default: nil, }, }, }, @@ -1400,9 +2370,9 @@ func TestDataDefault(t *testing.T) { Description: fwschemadata.DataDescriptionState, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "number_attribute": testschema.Attribute{ + "number_attribute": testschema.AttributeWithNumberDefaultValue{ Computed: true, - Type: types.NumberType, + Default: nil, }, }, }, @@ -1418,111 +2388,159 @@ func TestDataDefault(t *testing.T) { ), }, }, - "number-attribute-null-modified-default": { + "object-attribute-request-path": { data: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "number_attribute": testschema.AttributeWithNumberDefaultValue{ + "object_attribute": testschema.AttributeWithObjectDefaultValue{ + Optional: true, Computed: true, - Default: numberdefault.StaticBigFloat(big.NewFloat(5.4321)), + AttributeTypes: map[string]attr.Type{ + "test_attribute": types.StringType, + }, + Default: testdefaults.Object{ + DefaultObjectMethod: func(ctx context.Context, req defaults.ObjectRequest, resp *defaults.ObjectResponse) { + if !req.Path.Equal(path.Root("object_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("object_attribute"), req.Path), + ) + } + }, + }, }, }, }, TerraformValue: tftypes.NewValue( tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "number_attribute": tftypes.Number, + "object_attribute": tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + "object_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, nil), }, ), }, rawConfig: tftypes.NewValue(tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "number_attribute": tftypes.Number, + "object_attribute": tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig + "object_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, nil), }, ), expected: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "number_attribute": testschema.AttributeWithNumberDefaultValue{ + "object_attribute": testschema.AttributeWithObjectDefaultValue{ + Optional: true, Computed: true, - Default: numberdefault.StaticBigFloat(big.NewFloat(5.4321)), + AttributeTypes: map[string]attr.Type{ + "test_attribute": types.StringType, + }, + Default: testdefaults.Object{ + DefaultObjectMethod: func(ctx context.Context, req defaults.ObjectRequest, resp *defaults.ObjectResponse) { + if !req.Path.Equal(path.Root("object_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("object_attribute"), req.Path), + ) + } + }, + }, }, }, }, TerraformValue: tftypes.NewValue( tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "number_attribute": tftypes.Number, + "object_attribute": tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(5.4321)), + "object_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, nil), }, ), }, }, - "number-attribute-null-unmodified-default-nil": { + "object-attribute-response-diagnostics": { data: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "number_attribute": testschema.AttributeWithNumberDefaultValue{ + "object_attribute": testschema.AttributeWithObjectDefaultValue{ + Optional: true, Computed: true, - Default: nil, + AttributeTypes: map[string]attr.Type{ + "test_attribute": types.StringType, + }, + Default: testdefaults.Object{ + DefaultObjectMethod: func(ctx context.Context, req defaults.ObjectRequest, resp *defaults.ObjectResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, }, }, }, TerraformValue: tftypes.NewValue( tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "number_attribute": tftypes.Number, + "object_attribute": tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + "object_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, nil), }, ), }, rawConfig: tftypes.NewValue(tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "number_attribute": tftypes.Number, + "object_attribute": tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, nil), // value in rawConfig + "object_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, nil), }, ), expected: &fwschemadata.Data{ - Description: fwschemadata.DataDescriptionState, + Description: fwschemadata.DataDescriptionPlan, Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ - "number_attribute": testschema.AttributeWithNumberDefaultValue{ + "object_attribute": testschema.AttributeWithObjectDefaultValue{ + Optional: true, Computed: true, - Default: nil, + AttributeTypes: map[string]attr.Type{ + "test_attribute": types.StringType, + }, + Default: testdefaults.Object{ + DefaultObjectMethod: func(ctx context.Context, req defaults.ObjectRequest, resp *defaults.ObjectResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, }, }, }, TerraformValue: tftypes.NewValue( tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ - "number_attribute": tftypes.Number, + "object_attribute": tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, }, }, map[string]tftypes.Value{ - "number_attribute": tftypes.NewValue(tftypes.Number, big.NewFloat(1.2345)), + "object_attribute": tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"test_attribute": tftypes.String}}, nil), }, ), }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, }, "object-attribute-not-null-unmodified-default": { data: &fwschemadata.Data{ @@ -1851,6 +2869,152 @@ func TestDataDefault(t *testing.T) { ), }, }, + "set-attribute-request-path": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "set_attribute": testschema.AttributeWithSetDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.Set{ + DefaultSetMethod: func(ctx context.Context, req defaults.SetRequest, resp *defaults.SetResponse) { + if !req.Path.Equal(path.Root("set_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("set_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "set_attribute": tftypes.Set{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "set_attribute": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "set_attribute": tftypes.Set{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "set_attribute": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "set_attribute": testschema.AttributeWithSetDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.Set{ + DefaultSetMethod: func(ctx context.Context, req defaults.SetRequest, resp *defaults.SetResponse) { + if !req.Path.Equal(path.Root("set_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("set_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "set_attribute": tftypes.Set{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "set_attribute": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + }, + ), + }, + }, + "set-attribute-response-diagnostics": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "set_attribute": testschema.AttributeWithSetDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.Set{ + DefaultSetMethod: func(ctx context.Context, req defaults.SetRequest, resp *defaults.SetResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "set_attribute": tftypes.Set{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "set_attribute": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "set_attribute": tftypes.Set{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "set_attribute": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "set_attribute": testschema.AttributeWithSetDefaultValue{ + Optional: true, + Computed: true, + ElementType: types.StringType, + Default: testdefaults.Set{ + DefaultSetMethod: func(ctx context.Context, req defaults.SetRequest, resp *defaults.SetResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "set_attribute": tftypes.Set{ElementType: tftypes.String}, + }, + }, + map[string]tftypes.Value{ + "set_attribute": tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, nil), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, + }, "set-attribute-not-null-unmodified-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, @@ -2170,6 +3334,148 @@ func TestDataDefault(t *testing.T) { ), }, }, + "string-attribute-request-path": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "string_attribute": testschema.AttributeWithStringDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.String{ + DefaultStringMethod: func(ctx context.Context, req defaults.StringRequest, resp *defaults.StringResponse) { + if !req.Path.Equal(path.Root("string_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("string_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "string_attribute": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "string_attribute": tftypes.NewValue(tftypes.String, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "string_attribute": testschema.AttributeWithStringDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.String{ + DefaultStringMethod: func(ctx context.Context, req defaults.StringRequest, resp *defaults.StringResponse) { + if !req.Path.Equal(path.Root("string_attribute")) { + resp.Diagnostics.AddError( + "unexpected req.Path value", + fmt.Sprintf("expected %s, got: %s", path.Root("string_attribute"), req.Path), + ) + } + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "string_attribute": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + }, + "string-attribute-response-diagnostics": { + data: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "string_attribute": testschema.AttributeWithStringDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.String{ + DefaultStringMethod: func(ctx context.Context, req defaults.StringRequest, resp *defaults.StringResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "string_attribute": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + rawConfig: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "string_attribute": tftypes.NewValue(tftypes.String, nil), + }, + ), + expected: &fwschemadata.Data{ + Description: fwschemadata.DataDescriptionPlan, + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "string_attribute": testschema.AttributeWithStringDefaultValue{ + Optional: true, + Computed: true, + Default: testdefaults.String{ + DefaultStringMethod: func(ctx context.Context, req defaults.StringRequest, resp *defaults.StringResponse) { + resp.Diagnostics.AddError("test error summary", "test error detail") + resp.Diagnostics.AddWarning("test warning summary", "test warning detail") + }, + }, + }, + }, + }, + TerraformValue: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "string_attribute": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "string_attribute": tftypes.NewValue(tftypes.String, nil), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + diag.NewErrorDiagnostic("test error summary", "test error detail"), + diag.NewWarningDiagnostic("test warning summary", "test warning detail"), + }, + }, "string-attribute-not-null-unmodified-default": { data: &fwschemadata.Data{ Description: fwschemadata.DataDescriptionState, diff --git a/internal/testing/testdefaults/bool.go b/internal/testing/testdefaults/bool.go new file mode 100644 index 000000000..58bb7f631 --- /dev/null +++ b/internal/testing/testdefaults/bool.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.Bool = Bool{} + +// Declarative defaults.Bool for unit testing. +type Bool struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.Bool interface methods + DefaultBoolMethod func(context.Context, defaults.BoolRequest, *defaults.BoolResponse) +} + +// Description satisfies the defaults.Describer interface. +func (v Bool) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v Bool) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultBool satisfies the defaults.Bool interface. +func (v Bool) DefaultBool(ctx context.Context, req defaults.BoolRequest, resp *defaults.BoolResponse) { + if v.DefaultBoolMethod == nil { + return + } + + v.DefaultBoolMethod(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/doc.go b/internal/testing/testdefaults/doc.go new file mode 100644 index 000000000..b35a5061d --- /dev/null +++ b/internal/testing/testdefaults/doc.go @@ -0,0 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Package testdefaults contains declarative resource/schema/defaults +// implementations for unit testing. +package testdefaults diff --git a/internal/testing/testdefaults/float64.go b/internal/testing/testdefaults/float64.go new file mode 100644 index 000000000..46b3983d4 --- /dev/null +++ b/internal/testing/testdefaults/float64.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.Float64 = Float64{} + +// Declarative defaults.Float64 for unit testing. +type Float64 struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.Float64 interface methods + DefaultFloat64Method func(context.Context, defaults.Float64Request, *defaults.Float64Response) +} + +// Description satisfies the defaults.Describer interface. +func (v Float64) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v Float64) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultFloat64 satisfies the defaults.Float64 interface. +func (v Float64) DefaultFloat64(ctx context.Context, req defaults.Float64Request, resp *defaults.Float64Response) { + if v.DefaultFloat64Method == nil { + return + } + + v.DefaultFloat64Method(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/int64.go b/internal/testing/testdefaults/int64.go new file mode 100644 index 000000000..ea9661138 --- /dev/null +++ b/internal/testing/testdefaults/int64.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.Int64 = Int64{} + +// Declarative defaults.Int64 for unit testing. +type Int64 struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.Int64 interface methods + DefaultInt64Method func(context.Context, defaults.Int64Request, *defaults.Int64Response) +} + +// Description satisfies the defaults.Describer interface. +func (v Int64) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v Int64) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultInt64 satisfies the defaults.Int64 interface. +func (v Int64) DefaultInt64(ctx context.Context, req defaults.Int64Request, resp *defaults.Int64Response) { + if v.DefaultInt64Method == nil { + return + } + + v.DefaultInt64Method(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/list.go b/internal/testing/testdefaults/list.go new file mode 100644 index 000000000..5a2d3d3e5 --- /dev/null +++ b/internal/testing/testdefaults/list.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.List = List{} + +// Declarative defaults.List for unit testing. +type List struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.List interface methods + DefaultListMethod func(context.Context, defaults.ListRequest, *defaults.ListResponse) +} + +// Description satisfies the defaults.Describer interface. +func (v List) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v List) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultList satisfies the defaults.List interface. +func (v List) DefaultList(ctx context.Context, req defaults.ListRequest, resp *defaults.ListResponse) { + if v.DefaultListMethod == nil { + return + } + + v.DefaultListMethod(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/map.go b/internal/testing/testdefaults/map.go new file mode 100644 index 000000000..cc766a2de --- /dev/null +++ b/internal/testing/testdefaults/map.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.Map = Map{} + +// Declarative defaults.Map for unit testing. +type Map struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.Map interface methods + DefaultMapMethod func(context.Context, defaults.MapRequest, *defaults.MapResponse) +} + +// Description satisfies the defaults.Describer interface. +func (v Map) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v Map) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultMap satisfies the defaults.Map interface. +func (v Map) DefaultMap(ctx context.Context, req defaults.MapRequest, resp *defaults.MapResponse) { + if v.DefaultMapMethod == nil { + return + } + + v.DefaultMapMethod(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/number.go b/internal/testing/testdefaults/number.go new file mode 100644 index 000000000..b95392771 --- /dev/null +++ b/internal/testing/testdefaults/number.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.Number = Number{} + +// Declarative defaults.Number for unit testing. +type Number struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.Number interface methods + DefaultNumberMethod func(context.Context, defaults.NumberRequest, *defaults.NumberResponse) +} + +// Description satisfies the defaults.Describer interface. +func (v Number) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v Number) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultNumber satisfies the defaults.Number interface. +func (v Number) DefaultNumber(ctx context.Context, req defaults.NumberRequest, resp *defaults.NumberResponse) { + if v.DefaultNumberMethod == nil { + return + } + + v.DefaultNumberMethod(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/object.go b/internal/testing/testdefaults/object.go new file mode 100644 index 000000000..e5bd52e54 --- /dev/null +++ b/internal/testing/testdefaults/object.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.Object = Object{} + +// Declarative defaults.Object for unit testing. +type Object struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.Object interface methods + DefaultObjectMethod func(context.Context, defaults.ObjectRequest, *defaults.ObjectResponse) +} + +// Description satisfies the defaults.Describer interface. +func (v Object) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v Object) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultObject satisfies the defaults.Object interface. +func (v Object) DefaultObject(ctx context.Context, req defaults.ObjectRequest, resp *defaults.ObjectResponse) { + if v.DefaultObjectMethod == nil { + return + } + + v.DefaultObjectMethod(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/set.go b/internal/testing/testdefaults/set.go new file mode 100644 index 000000000..2ce2e311a --- /dev/null +++ b/internal/testing/testdefaults/set.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.Set = Set{} + +// Declarative defaults.Set for unit testing. +type Set struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.Set interface methods + DefaultSetMethod func(context.Context, defaults.SetRequest, *defaults.SetResponse) +} + +// Description satisfies the defaults.Describer interface. +func (v Set) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v Set) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultSet satisfies the defaults.Set interface. +func (v Set) DefaultSet(ctx context.Context, req defaults.SetRequest, resp *defaults.SetResponse) { + if v.DefaultSetMethod == nil { + return + } + + v.DefaultSetMethod(ctx, req, resp) +} diff --git a/internal/testing/testdefaults/string.go b/internal/testing/testdefaults/string.go new file mode 100644 index 000000000..2d6c885b2 --- /dev/null +++ b/internal/testing/testdefaults/string.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testdefaults + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" +) + +var _ defaults.String = String{} + +// Declarative defaults.String for unit testing. +type String struct { + // defaults.Describer interface methods + DescriptionMethod func(context.Context) string + MarkdownDescriptionMethod func(context.Context) string + + // defaults.String interface methods + DefaultStringMethod func(context.Context, defaults.StringRequest, *defaults.StringResponse) +} + +// Description satisfies the defaults.Describer interface. +func (v String) Description(ctx context.Context) string { + if v.DescriptionMethod == nil { + return "" + } + + return v.DescriptionMethod(ctx) +} + +// MarkdownDescription satisfies the defaults.Describer interface. +func (v String) MarkdownDescription(ctx context.Context) string { + if v.MarkdownDescriptionMethod == nil { + return "" + } + + return v.MarkdownDescriptionMethod(ctx) +} + +// DefaultString satisfies the defaults.String interface. +func (v String) DefaultString(ctx context.Context, req defaults.StringRequest, resp *defaults.StringResponse) { + if v.DefaultStringMethod == nil { + return + } + + v.DefaultStringMethod(ctx, req, resp) +}