From 5930e21c801bb48f60e44d4291b393a00ede5925 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 19 Mar 2024 15:52:31 +0000 Subject: [PATCH 01/62] Add ValidateableAttribute and ValidateableParameter interfaces --- types/validation/attribute.go | 36 +++++++++++++++++++++++++++ types/validation/bool_attribute.go | 17 +++++++++++++ types/validation/bool_parameter.go | 17 +++++++++++++ types/validation/doc.go | 5 ++++ types/validation/float64_attribute.go | 17 +++++++++++++ types/validation/float64_parameter.go | 17 +++++++++++++ types/validation/int64_attribute.go | 17 +++++++++++++ types/validation/int64_parameter.go | 17 +++++++++++++ types/validation/list_attribute.go | 17 +++++++++++++ types/validation/list_parameter.go | 17 +++++++++++++ types/validation/map_attribute.go | 17 +++++++++++++ types/validation/map_parameter.go | 17 +++++++++++++ types/validation/number_attribute.go | 17 +++++++++++++ types/validation/number_parameter.go | 17 +++++++++++++ types/validation/object_attribute.go | 17 +++++++++++++ types/validation/object_parameter.go | 17 +++++++++++++ types/validation/parameter.go | 34 +++++++++++++++++++++++++ types/validation/set_attribute.go | 17 +++++++++++++ types/validation/set_parameter.go | 17 +++++++++++++ types/validation/string_attribute.go | 17 +++++++++++++ types/validation/string_parameter.go | 17 +++++++++++++ 21 files changed, 381 insertions(+) create mode 100644 types/validation/attribute.go create mode 100644 types/validation/bool_attribute.go create mode 100644 types/validation/bool_parameter.go create mode 100644 types/validation/doc.go create mode 100644 types/validation/float64_attribute.go create mode 100644 types/validation/float64_parameter.go create mode 100644 types/validation/int64_attribute.go create mode 100644 types/validation/int64_parameter.go create mode 100644 types/validation/list_attribute.go create mode 100644 types/validation/list_parameter.go create mode 100644 types/validation/map_attribute.go create mode 100644 types/validation/map_parameter.go create mode 100644 types/validation/number_attribute.go create mode 100644 types/validation/number_parameter.go create mode 100644 types/validation/object_attribute.go create mode 100644 types/validation/object_parameter.go create mode 100644 types/validation/parameter.go create mode 100644 types/validation/set_attribute.go create mode 100644 types/validation/set_parameter.go create mode 100644 types/validation/string_attribute.go create mode 100644 types/validation/string_parameter.go diff --git a/types/validation/attribute.go b/types/validation/attribute.go new file mode 100644 index 000000000..032f51d1e --- /dev/null +++ b/types/validation/attribute.go @@ -0,0 +1,36 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" +) + +// ValidateableAttribute defines an interface for validating an attribute value. +type ValidateableAttribute interface { + // ValidateAttribute returns any warnings or errors generated during validation + // of the attribute. It is generally used to check the data format and ensure + // that it complies with the requirements of the Value. + ValidateAttribute(context.Context, ValidateAttributeRequest, *ValidateAttributeResponse) +} + +// ValidateAttributeRequest represents a request for the Value to call its +// validation logic. An instance of this request struct is supplied as an +// argument to the ValidateAttribute method. +type ValidateAttributeRequest struct { + // Path is the path to the attribute being validated. + Path path.Path +} + +// ValidateAttributeResponse represents a response to a ValidateAttributeRequest. +// An instance of this response struct is supplied as an argument to the +// ValidateAttribute method. +type ValidateAttributeResponse struct { + // Diagnostics is a collection of warnings or errors generated during + // validation of the Value. + Diagnostics diag.Diagnostics +} diff --git a/types/validation/bool_attribute.go b/types/validation/bool_attribute.go new file mode 100644 index 000000000..b1e923260 --- /dev/null +++ b/types/validation/bool_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// BoolAttributeWithValidate extends the basetypes.BoolValuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type BoolAttributeWithValidate interface { + basetypes.BoolValuable + + ValidateableAttribute +} diff --git a/types/validation/bool_parameter.go b/types/validation/bool_parameter.go new file mode 100644 index 000000000..c37c7ef57 --- /dev/null +++ b/types/validation/bool_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// BoolParameterWithValidate extends the basetypes.BoolValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type BoolParameterWithValidate interface { + basetypes.BoolValuable + + ValidateableParameter +} diff --git a/types/validation/doc.go b/types/validation/doc.go new file mode 100644 index 000000000..24ced450b --- /dev/null +++ b/types/validation/doc.go @@ -0,0 +1,5 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Package validation contains additional interfaces for base types. +package validation diff --git a/types/validation/float64_attribute.go b/types/validation/float64_attribute.go new file mode 100644 index 000000000..2b105090e --- /dev/null +++ b/types/validation/float64_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// Float64AttributeWithValidate extends the basetypes.Float64Valuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type Float64AttributeWithValidate interface { + basetypes.Float64Valuable + + ValidateableAttribute +} diff --git a/types/validation/float64_parameter.go b/types/validation/float64_parameter.go new file mode 100644 index 000000000..05b39034c --- /dev/null +++ b/types/validation/float64_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// Float64ParameterWithValidate extends the basetypes.Float64Valuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type Float64ParameterWithValidate interface { + basetypes.Float64Valuable + + ValidateableParameter +} diff --git a/types/validation/int64_attribute.go b/types/validation/int64_attribute.go new file mode 100644 index 000000000..fa62ddfe5 --- /dev/null +++ b/types/validation/int64_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// Int64AttributeWithValidate extends the basetypes.Int64Valuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type Int64AttributeWithValidate interface { + basetypes.Int64Valuable + + ValidateableAttribute +} diff --git a/types/validation/int64_parameter.go b/types/validation/int64_parameter.go new file mode 100644 index 000000000..8161cef26 --- /dev/null +++ b/types/validation/int64_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// Int64ParameterWithValidate extends the basetypes.Int64Valuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type Int64ParameterWithValidate interface { + basetypes.Int64Valuable + + ValidateableParameter +} diff --git a/types/validation/list_attribute.go b/types/validation/list_attribute.go new file mode 100644 index 000000000..b4dc4ea95 --- /dev/null +++ b/types/validation/list_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// ListAttributeWithValidate extends the basetypes.ListValuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type ListAttributeWithValidate interface { + basetypes.ListValuable + + ValidateableAttribute +} diff --git a/types/validation/list_parameter.go b/types/validation/list_parameter.go new file mode 100644 index 000000000..8507e5813 --- /dev/null +++ b/types/validation/list_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// ListParameterWithValidate extends the basetypes.ListValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type ListParameterWithValidate interface { + basetypes.ListValuable + + ValidateableParameter +} diff --git a/types/validation/map_attribute.go b/types/validation/map_attribute.go new file mode 100644 index 000000000..78b0d1ec9 --- /dev/null +++ b/types/validation/map_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// MapAttributeWithValidate extends the basetypes.MapValuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type MapAttributeWithValidate interface { + basetypes.MapValuable + + ValidateableAttribute +} diff --git a/types/validation/map_parameter.go b/types/validation/map_parameter.go new file mode 100644 index 000000000..3c369f1c0 --- /dev/null +++ b/types/validation/map_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// MapParameterWithValidate extends the basetypes.MapValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type MapParameterWithValidate interface { + basetypes.MapValuable + + ValidateableParameter +} diff --git a/types/validation/number_attribute.go b/types/validation/number_attribute.go new file mode 100644 index 000000000..1752e6157 --- /dev/null +++ b/types/validation/number_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// NumberAttributeWithValidate extends the basetypes.NumberValuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type NumberAttributeWithValidate interface { + basetypes.NumberValuable + + ValidateableAttribute +} diff --git a/types/validation/number_parameter.go b/types/validation/number_parameter.go new file mode 100644 index 000000000..ba9cee87f --- /dev/null +++ b/types/validation/number_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// NumberParameterWithValidate extends the basetypes.NumberValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type NumberParameterWithValidate interface { + basetypes.NumberValuable + + ValidateableParameter +} diff --git a/types/validation/object_attribute.go b/types/validation/object_attribute.go new file mode 100644 index 000000000..23f389b4f --- /dev/null +++ b/types/validation/object_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// ObjectAttributeWithValidate extends the basetypes.ObjectValuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type ObjectAttributeWithValidate interface { + basetypes.ObjectValuable + + ValidateableAttribute +} diff --git a/types/validation/object_parameter.go b/types/validation/object_parameter.go new file mode 100644 index 000000000..194172cb2 --- /dev/null +++ b/types/validation/object_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// ObjectParameterWithValidate extends the basetypes.ObjectValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type ObjectParameterWithValidate interface { + basetypes.ObjectValuable + + ValidateableParameter +} diff --git a/types/validation/parameter.go b/types/validation/parameter.go new file mode 100644 index 000000000..273520a33 --- /dev/null +++ b/types/validation/parameter.go @@ -0,0 +1,34 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" +) + +// ValidateableParameter defines an interface for validating a parameter value. +type ValidateableParameter interface { + // ValidateParameter returns any error generated during validation + // of the parameter. It is generally used to check the data format and ensure + // that it complies with the requirements of the Value. + ValidateParameter(context.Context, ValidateParameterRequest, *ValidateParameterResponse) +} + +// ValidateParameterRequest represents a request for the Value to call its +// validation logic. An instance of this request struct is supplied as an +// argument to the Value type ValidateParameter method. +type ValidateParameterRequest struct { + // Position is the zero-ordered position of the parameter being validated. + Position int64 +} + +// ValidateParameterResponse represents a response to a ValidateParameterRequest. +// An instance of this response struct is supplied as an argument to the +// ValidateParameter method. +type ValidateParameterResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/types/validation/set_attribute.go b/types/validation/set_attribute.go new file mode 100644 index 000000000..8b636ab65 --- /dev/null +++ b/types/validation/set_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// SetAttributeWithValidate extends the basetypes.SetValuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type SetAttributeWithValidate interface { + basetypes.SetValuable + + ValidateableAttribute +} diff --git a/types/validation/set_parameter.go b/types/validation/set_parameter.go new file mode 100644 index 000000000..448bca0d9 --- /dev/null +++ b/types/validation/set_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// SetParameterWithValidate extends the basetypes.SetValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type SetParameterWithValidate interface { + basetypes.SetValuable + + ValidateableParameter +} diff --git a/types/validation/string_attribute.go b/types/validation/string_attribute.go new file mode 100644 index 000000000..48b987bc1 --- /dev/null +++ b/types/validation/string_attribute.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// StringAttributeWithValidate extends the basetypes.StringValuable interface to include a +// ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type StringAttributeWithValidate interface { + basetypes.StringValuable + + ValidateableAttribute +} diff --git a/types/validation/string_parameter.go b/types/validation/string_parameter.go new file mode 100644 index 000000000..307becdb7 --- /dev/null +++ b/types/validation/string_parameter.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// StringParameterWithValidate extends the basetypes.StringValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type StringParameterWithValidate interface { + basetypes.StringValuable + + ValidateableParameter +} From e3b5956840f4a9ba95c620a7ae17d6bc53e0662d Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 19 Mar 2024 15:52:52 +0000 Subject: [PATCH 02/62] Deprecate xattr.TypeWithValidate --- attr/xattr/type.go | 6 +++++- internal/fromproto5/arguments_data.go | 8 +++++--- internal/fromproto6/arguments_data.go | 8 +++++--- internal/fwschemadata/data_set_at_path.go | 13 ++++++++----- internal/fwschemadata/data_value.go | 8 +++++--- internal/reflect/interfaces.go | 10 +++++++++- internal/reflect/map.go | 6 +++++- internal/reflect/number.go | 5 +++++ internal/reflect/pointer.go | 4 +++- internal/reflect/primitive.go | 5 ++++- internal/reflect/slice.go | 7 ++++++- internal/reflect/struct.go | 5 ++++- internal/testing/testtypes/boolwithvalidate.go | 5 ++++- internal/testing/testtypes/listwithvalidate.go | 5 ++++- internal/testing/testtypes/mapwithvalidate.go | 5 ++++- internal/testing/testtypes/numberwithvalidate.go | 5 ++++- internal/testing/testtypes/setwithvalidate.go | 5 ++++- internal/testing/testtypes/stringwithvalidate.go | 5 ++++- types/basetypes/float64_type.go | 4 +++- types/basetypes/int64_type.go | 4 +++- types/basetypes/list_type.go | 4 +++- types/basetypes/map_type.go | 4 +++- types/basetypes/set_type.go | 7 +++++-- 23 files changed, 105 insertions(+), 33 deletions(-) diff --git a/attr/xattr/type.go b/attr/xattr/type.go index 77b573106..c7e5b0f83 100644 --- a/attr/xattr/type.go +++ b/attr/xattr/type.go @@ -6,14 +6,18 @@ package xattr 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/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // TypeWithValidate extends the attr.Type interface to include a Validate // method, used to bundle consistent validation logic with the Type. +// +// Deprecated: Use the value type-specific AttributeWithValidate and +// ParameterWithValidate interfaces in the validation package instead. type TypeWithValidate interface { attr.Type diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 3ce46cffd..509bf5b6d 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" @@ -14,7 +16,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // ArgumentsData returns the ArgumentsData for a given []*tfprotov5.DynamicValue @@ -112,11 +113,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def // which will always be incorrect in the context of functions. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if attrTypeWithValidate, ok := parameterType.(xattr.TypeWithValidate); ok { logging.FrameworkTrace(ctx, "Parameter type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path.Empty())...) - logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") if diags.HasError() { continue diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 4dd6db7bc..4cf6de8ad 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" @@ -14,7 +16,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ArgumentsData returns the ArgumentsData for a given []*tfprotov6.DynamicValue @@ -112,11 +113,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def // which will always be incorrect in the context of functions. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if attrTypeWithValidate, ok := parameterType.(xattr.TypeWithValidate); ok { logging.FrameworkTrace(ctx, "Parameter type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path.Empty())...) - logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") if diags.HasError() { continue diff --git a/internal/fwschemadata/data_set_at_path.go b/internal/fwschemadata/data_set_at_path.go index c7febc8c7..6fb075c7c 100644 --- a/internal/fwschemadata/data_set_at_path.go +++ b/internal/fwschemadata/data_set_at_path.go @@ -8,13 +8,14 @@ import ( "errors" "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/reflect" "github.com/hashicorp/terraform-plugin-framework/internal/totftypes" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // SetAtPath sets the attribute at `path` using the supplied Go value. @@ -69,11 +70,12 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d return diags } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if attrTypeWithValidate, ok := attrType.(xattr.TypeWithValidate); ok { logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") diags.Append(attrTypeWithValidate.Validate(ctx, tfVal, path)...) - logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") if diags.HasError() { return diags @@ -187,11 +189,12 @@ func (d Data) SetAtPathTransformFunc(ctx context.Context, path path.Path, tfVal return nil, diags } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if attrTypeWithValidate, ok := parentAttrType.(xattr.TypeWithValidate); ok { logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") diags.Append(attrTypeWithValidate.Validate(ctx, parentValue, parentPath)...) - logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") if diags.HasError() { return nil, diags diff --git a/internal/fwschemadata/data_value.go b/internal/fwschemadata/data_value.go index 2a1be8c54..f74c52f83 100644 --- a/internal/fwschemadata/data_value.go +++ b/internal/fwschemadata/data_value.go @@ -7,13 +7,14 @@ import ( "context" "errors" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/totftypes" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // ValueAtPath retrieves the attribute found at `path` and returns it as an @@ -76,11 +77,12 @@ func (d Data) ValueAtPath(ctx context.Context, schemaPath path.Path) (attr.Value // If found, convert this value to an unknown value. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186 + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if attrTypeWithValidate, ok := attrType.(xattr.TypeWithValidate); ok { logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, schemaPath)...) - logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") if diags.HasError() { return nil, diags diff --git a/internal/reflect/interfaces.go b/internal/reflect/interfaces.go index 8c5a95409..e458f95e3 100644 --- a/internal/reflect/interfaces.go +++ b/internal/reflect/interfaces.go @@ -8,11 +8,12 @@ import ( "fmt" "reflect" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Unknownable is an interface for types that can be explicitly set to known or @@ -74,6 +75,7 @@ func FromUnknownable(ctx context.Context, typ attr.Type, val Unknownable, path p if val.GetUnknown(ctx) { tfVal := tftypes.NewValue(typ.TerraformType(ctx), tftypes.UnknownValue) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) @@ -95,6 +97,7 @@ func FromUnknownable(ctx context.Context, typ attr.Type, val Unknownable, path p tfVal := tftypes.NewValue(typ.TerraformType(ctx), val.GetValue(ctx)) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) @@ -168,6 +171,7 @@ func FromNullable(ctx context.Context, typ attr.Type, val Nullable, path path.Pa if val.GetNull(ctx) { tfVal := tftypes.NewValue(typ.TerraformType(ctx), nil) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) @@ -189,6 +193,7 @@ func FromNullable(ctx context.Context, typ attr.Type, val Nullable, path path.Pa tfVal := tftypes.NewValue(typ.TerraformType(ctx), val.GetValue(ctx)) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) @@ -260,6 +265,7 @@ func FromValueCreator(ctx context.Context, typ attr.Type, val tftypes.ValueCreat } tfVal := tftypes.NewValue(typ.TerraformType(ctx), raw) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) @@ -283,6 +289,7 @@ func FromValueCreator(ctx context.Context, typ attr.Type, val tftypes.ValueCreat func NewAttributeValue(ctx context.Context, typ attr.Type, val tftypes.Value, target reflect.Value, opts Options, path path.Path) (reflect.Value, diag.Diagnostics) { var diags diag.Diagnostics + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, val, path)...) @@ -334,6 +341,7 @@ func FromAttributeValue(ctx context.Context, typ attr.Type, val attr.Value, path return nil, diags } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { tfVal, err := val.ToTerraformValue(ctx) if err != nil { diff --git a/internal/reflect/map.go b/internal/reflect/map.go index 6bd0b8563..57c3d5a1b 100644 --- a/internal/reflect/map.go +++ b/internal/reflect/map.go @@ -8,11 +8,12 @@ import ( "fmt" "reflect" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Map creates a map value that matches the type of `target`, and populates it @@ -103,6 +104,7 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu if val.IsNil() { tfVal := tftypes.NewValue(tfType, nil) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) @@ -148,6 +150,7 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu return nil, append(diags, toTerraformValueErrorDiag(err, path)) } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := elemType.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path.AtMapKey(key.String()))...) @@ -166,6 +169,7 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu tfVal := tftypes.NewValue(tfType, tfElems) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) diff --git a/internal/reflect/number.go b/internal/reflect/number.go index 3b48d6114..c467e50f0 100644 --- a/internal/reflect/number.go +++ b/internal/reflect/number.go @@ -179,6 +179,7 @@ func FromInt(ctx context.Context, typ attr.Type, val int64, path path.Path) (att } tfNum := tftypes.NewValue(tftypes.Number, val) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) @@ -206,6 +207,7 @@ func FromUint(ctx context.Context, typ attr.Type, val uint64, path path.Path) (a } tfNum := tftypes.NewValue(tftypes.Number, val) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) @@ -233,6 +235,7 @@ func FromFloat(ctx context.Context, typ attr.Type, val float64, path path.Path) } tfNum := tftypes.NewValue(tftypes.Number, val) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) @@ -260,6 +263,7 @@ func FromBigFloat(ctx context.Context, typ attr.Type, val *big.Float, path path. } tfNum := tftypes.NewValue(tftypes.Number, val) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) @@ -288,6 +292,7 @@ func FromBigInt(ctx context.Context, typ attr.Type, val *big.Int, path path.Path } tfNum := tftypes.NewValue(tftypes.Number, fl) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) diff --git a/internal/reflect/pointer.go b/internal/reflect/pointer.go index 1628acec3..65be2b841 100644 --- a/internal/reflect/pointer.go +++ b/internal/reflect/pointer.go @@ -8,11 +8,12 @@ import ( "fmt" "reflect" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Pointer builds a new zero value of the concrete type that `target` @@ -93,6 +94,7 @@ func FromPointer(ctx context.Context, typ attr.Type, value reflect.Value, path p if value.IsNil() { tfVal := tftypes.NewValue(typ.TerraformType(ctx), nil) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) diff --git a/internal/reflect/primitive.go b/internal/reflect/primitive.go index 3def51593..d67daf015 100644 --- a/internal/reflect/primitive.go +++ b/internal/reflect/primitive.go @@ -8,11 +8,12 @@ import ( "errors" "reflect" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Primitive builds a string or boolean, depending on the type of `target`, and @@ -68,6 +69,7 @@ func FromString(ctx context.Context, typ attr.Type, val string, path path.Path) } tfStr := tftypes.NewValue(tftypes.String, val) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfStr, path)...) @@ -95,6 +97,7 @@ func FromBool(ctx context.Context, typ attr.Type, val bool, path path.Path) (att } tfBool := tftypes.NewValue(tftypes.Bool, val) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfBool, path)...) diff --git a/internal/reflect/slice.go b/internal/reflect/slice.go index 5ffaddd9c..0dd438005 100644 --- a/internal/reflect/slice.go +++ b/internal/reflect/slice.go @@ -8,11 +8,12 @@ import ( "fmt" "reflect" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // build a slice of elements, matching the type of `target`, and fill it with @@ -185,6 +186,7 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. if val.IsNil() { tfVal := tftypes.NewValue(tfType, nil) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) @@ -236,6 +238,7 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. valPath = path.AtSetValue(val) } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := elemType.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, valPath)...) if diags.HasError() { @@ -303,6 +306,7 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. return nil, append(diags, toTerraformValueErrorDiag(err, path)) } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := elemAttrType.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, valPath)...) if diags.HasError() { @@ -329,6 +333,7 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. tfVal := tftypes.NewValue(tfType, tfElems) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) diff --git a/internal/reflect/struct.go b/internal/reflect/struct.go index da646b85d..3853486b7 100644 --- a/internal/reflect/struct.go +++ b/internal/reflect/struct.go @@ -9,11 +9,12 @@ import ( "reflect" "strings" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Struct builds a new struct using the data in `object`, as long as `object` @@ -226,6 +227,7 @@ func FromStruct(ctx context.Context, typ attr.TypeWithAttributeTypes, val reflec return nil, append(diags, toTerraformValueErrorDiag(err, path)) } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfObjVal, path)...) @@ -242,6 +244,7 @@ func FromStruct(ctx context.Context, typ attr.TypeWithAttributeTypes, val reflec AttributeTypes: objTypes, }, objValues) + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) diff --git a/internal/testing/testtypes/boolwithvalidate.go b/internal/testing/testtypes/boolwithvalidate.go index 07b919580..8ab86efbb 100644 --- a/internal/testing/testtypes/boolwithvalidate.go +++ b/internal/testing/testtypes/boolwithvalidate.go @@ -7,15 +7,18 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var ( + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = BoolTypeWithValidateError{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = BoolTypeWithValidateWarning{} ) diff --git a/internal/testing/testtypes/listwithvalidate.go b/internal/testing/testtypes/listwithvalidate.go index c735e1a99..36435d1da 100644 --- a/internal/testing/testtypes/listwithvalidate.go +++ b/internal/testing/testtypes/listwithvalidate.go @@ -6,15 +6,18 @@ package testtypes import ( "context" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var ( + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = ListTypeWithValidateError{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = ListTypeWithValidateWarning{} ) diff --git a/internal/testing/testtypes/mapwithvalidate.go b/internal/testing/testtypes/mapwithvalidate.go index f808ac8ae..015f6346e 100644 --- a/internal/testing/testtypes/mapwithvalidate.go +++ b/internal/testing/testtypes/mapwithvalidate.go @@ -6,15 +6,18 @@ package testtypes import ( "context" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var ( + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = MapTypeWithValidateError{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = MapTypeWithValidateWarning{} ) diff --git a/internal/testing/testtypes/numberwithvalidate.go b/internal/testing/testtypes/numberwithvalidate.go index d24c91cc2..f0b6d6918 100644 --- a/internal/testing/testtypes/numberwithvalidate.go +++ b/internal/testing/testtypes/numberwithvalidate.go @@ -7,15 +7,18 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var ( + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = NumberTypeWithValidateError{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = NumberTypeWithValidateWarning{} ) diff --git a/internal/testing/testtypes/setwithvalidate.go b/internal/testing/testtypes/setwithvalidate.go index 10b1cc2db..9c7ddc13f 100644 --- a/internal/testing/testtypes/setwithvalidate.go +++ b/internal/testing/testtypes/setwithvalidate.go @@ -6,15 +6,18 @@ package testtypes import ( "context" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var ( + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = SetTypeWithValidateError{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = SetTypeWithValidateWarning{} ) diff --git a/internal/testing/testtypes/stringwithvalidate.go b/internal/testing/testtypes/stringwithvalidate.go index 314ff6716..b4f1dcd7f 100644 --- a/internal/testing/testtypes/stringwithvalidate.go +++ b/internal/testing/testtypes/stringwithvalidate.go @@ -7,15 +7,18 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var ( + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = StringTypeWithValidateError{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = StringTypeWithValidateWarning{} ) diff --git a/types/basetypes/float64_type.go b/types/basetypes/float64_type.go index 6c690690b..a783201e5 100644 --- a/types/basetypes/float64_type.go +++ b/types/basetypes/float64_type.go @@ -9,16 +9,18 @@ import ( "math" "math/big" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Float64Typable extends attr.Type for float64 types. // Implement this interface to create a custom Float64Type type. type Float64Typable interface { + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. xattr.TypeWithValidate // ValueFromFloat64 should convert the Float64 to a Float64Valuable type. diff --git a/types/basetypes/int64_type.go b/types/basetypes/int64_type.go index 5f2a8d343..93fa1b9e4 100644 --- a/types/basetypes/int64_type.go +++ b/types/basetypes/int64_type.go @@ -8,16 +8,18 @@ import ( "fmt" "math/big" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Int64Typable extends attr.Type for int64 types. // Implement this interface to create a custom Int64Type type. type Int64Typable interface { + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. xattr.TypeWithValidate // ValueFromInt64 should convert the Int64 to a Int64Valuable type. diff --git a/types/basetypes/list_type.go b/types/basetypes/list_type.go index 146f3a4fb..a53ae8d0c 100644 --- a/types/basetypes/list_type.go +++ b/types/basetypes/list_type.go @@ -7,11 +7,12 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var _ ListTypable = ListType{} @@ -157,6 +158,7 @@ func (l ListType) Validate(ctx context.Context, in tftypes.Value, path path.Path return diags } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. validatableType, isValidatable := l.ElementType().(xattr.TypeWithValidate) if !isValidatable { return diags diff --git a/types/basetypes/map_type.go b/types/basetypes/map_type.go index 0c356f67f..d1a8eec68 100644 --- a/types/basetypes/map_type.go +++ b/types/basetypes/map_type.go @@ -7,11 +7,12 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var _ MapTypable = MapType{} @@ -160,6 +161,7 @@ func (m MapType) Validate(ctx context.Context, in tftypes.Value, path path.Path) return diags } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. validatableType, isValidatable := m.ElementType().(xattr.TypeWithValidate) if !isValidatable { return diags diff --git a/types/basetypes/set_type.go b/types/basetypes/set_type.go index 1f89957f4..67ab3c40d 100644 --- a/types/basetypes/set_type.go +++ b/types/basetypes/set_type.go @@ -7,15 +7,17 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) var ( - _ SetTypable = SetType{} + _ SetTypable = SetType{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. _ xattr.TypeWithValidate = SetType{} ) @@ -160,6 +162,7 @@ func (st SetType) Validate(ctx context.Context, in tftypes.Value, path path.Path return diags } + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. validatableType, isValidatable := st.ElementType().(xattr.TypeWithValidate) // Attempting to use map[tftypes.Value]struct{} for duplicate detection yields: From 30cc1d9cc874ec30ad4cb1ffafcd6bd9ffcc1d3e Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 21 Mar 2024 09:18:36 +0000 Subject: [PATCH 03/62] Modify function signature of ArgumentsData() to return a function.FuncError and add switch to handle validation.ValidateableParameter interface --- internal/fromproto5/arguments_data.go | 149 +++++++++++-------- internal/fromproto5/arguments_data_test.go | 75 +++++----- internal/fromproto5/callfunction.go | 10 +- internal/fromproto5/callfunction_test.go | 18 +-- internal/fromproto6/arguments_data.go | 145 +++++++++++------- internal/fromproto6/arguments_data_test.go | 75 +++++----- internal/fromproto6/callfunction.go | 10 +- internal/fromproto6/callfunction_test.go | 18 +-- internal/proto5server/server_callfunction.go | 4 +- internal/proto6server/server_callfunction.go | 4 +- 10 files changed, 282 insertions(+), 226 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 509bf5b6d..4edca1a86 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -11,41 +11,37 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-framework/types/validation" ) // ArgumentsData returns the ArgumentsData for a given []*tfprotov5.DynamicValue // and function.Definition. -func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, definition function.Definition) (function.ArgumentsData, diag.Diagnostics) { +func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, definition function.Definition) (function.ArgumentsData, *function.FuncError) { if definition.VariadicParameter == nil && len(arguments) != len(definition.Parameters) { - return function.NewArgumentsData(nil), diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Expected function arguments: %d\n", len(definition.Parameters))+ - fmt.Sprintf("Given function arguments: %d", len(arguments)), - ), - } + return function.NewArgumentsData(nil), function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + fmt.Sprintf("Expected function arguments: %d\n", len(definition.Parameters)) + + fmt.Sprintf("Given function arguments: %d", len(arguments)), + ) } // Expect at least all parameters to have corresponding arguments. Variadic // parameter might have 0 to n arguments, which is why it is not checked in // this case. if len(arguments) < len(definition.Parameters) { - return function.NewArgumentsData(nil), diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Expected minimum function arguments: %d\n", len(definition.Parameters))+ - fmt.Sprintf("Given function arguments: %d", len(arguments)), - ), - } + return function.NewArgumentsData(nil), function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + fmt.Sprintf("Expected minimum function arguments: %d\n", len(definition.Parameters)) + + fmt.Sprintf("Given function arguments: %d", len(arguments)), + ) } if definition.VariadicParameter == nil && len(arguments) == 0 { @@ -55,74 +51,115 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def // Variadic values are collected as a separate tuple to ease developer usage. argumentValues := make([]attr.Value, 0, len(definition.Parameters)) variadicValues := make([]attr.Value, 0, len(arguments)-len(definition.Parameters)) - var diags diag.Diagnostics + var funcError *function.FuncError for position, argument := range arguments { parameter, parameterDiags := definition.Parameter(ctx, position) - diags.Append(parameterDiags...) + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) - if diags.HasError() { - return function.NewArgumentsData(nil), diags + if funcError != nil { + return function.NewArgumentsData(nil), funcError } parameterType := parameter.GetType() + pos := int64(position) + if parameterType == nil { - diags.AddError( - "Unable to Convert Function Argument", - "An unexpected error was encountered when converting the function argument from the protocol type. "+ + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Unable to Convert Function Argument: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ fmt.Sprintf("Parameter type missing at position %d", position), - ) + )) - return function.NewArgumentsData(nil), diags + return function.NewArgumentsData(nil), funcError } tfValue, err := argument.Unmarshal(parameterType.TerraformType(ctx)) if err != nil { - diags.AddError( - "Unable to Convert Function Argument", - "An unexpected error was encountered when converting the function argument from the protocol type. "+ + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Unable to Convert Function Argument: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ fmt.Sprintf("Unable to unmarshal DynamicValue at position %d: %s", position, err), - ) + )) - return function.NewArgumentsData(nil), diags + return function.NewArgumentsData(nil), funcError } attrValue, err := parameterType.ValueFromTerraform(ctx, tfValue) if err != nil { - diags.AddError( - "Unable to Convert Function Argument", - "An unexpected error was encountered when converting the function argument from the protocol type. "+ + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Unable to Convert Function Argument"+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %s", position, err), - ) + fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %stringVal", position, err), + )) - return function.NewArgumentsData(nil), diags + return function.NewArgumentsData(nil), funcError } - // This is intentionally below the attr.Value conversion so it can be - // updated for any new type system validation interfaces. Note that the + // This is intentionally below the conversion of tftypes.Value to attr.Value + // so it can be updated for any new type system validation interfaces. Note that the // original xattr.TypeWithValidation interface must set a path.Path, // which will always be incorrect in the context of functions. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if attrTypeWithValidate, ok := parameterType.(xattr.TypeWithValidate); ok { - logging.FrameworkTrace(ctx, "Parameter type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") - diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path.Empty())...) - logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") - - if diags.HasError() { + switch t := attrValue.(type) { + case validation.ValidateableParameter: + resp := validation.ValidateParameterResponse{} + + logging.FrameworkTrace(ctx, "Parameter value implements ValidateableParameter") + logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateParameter") + + t.ValidateParameter(ctx, + validation.ValidateParameterRequest{ + Position: pos, + }, + &resp, + ) + + logging.FrameworkTrace(ctx, "Called provider defined Value ValidateParameter") + + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + continue } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if t, ok := parameterType.(xattr.TypeWithValidate); ok { + logging.FrameworkTrace(ctx, "Parameter type implements TypeWithValidate") + logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + + diags := t.Validate(ctx, tfValue, path.Empty()) + + logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + + if diags.HasError() { + funcErrFromDiags := function.FuncErrorFromDiags(ctx, diags) + + if funcErrFromDiags != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + funcErrFromDiags.Error())) + } + + continue + } + } } if definition.VariadicParameter != nil && position >= len(definition.Parameters) { @@ -157,18 +194,14 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def variadicValue, variadicValueDiags := basetypes.NewTupleValue(tupleTypes, tupleValues) - diags.Append(variadicValueDiags...) + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, variadicValueDiags)) - if diags.HasError() { - return function.NewArgumentsData(argumentValues), diags + if funcError != nil { + return function.NewArgumentsData(argumentValues), funcError } argumentValues = append(argumentValues, variadicValue) } - if diags.HasError() { - return function.NewArgumentsData(nil), diags - } - - return function.NewArgumentsData(argumentValues), diags + return function.NewArgumentsData(argumentValues), funcError } diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 5dba9b16f..649bbb96a 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -8,25 +8,24 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "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/function" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" - "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tfprotov5" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestArgumentsData(t *testing.T) { t.Parallel() testCases := map[string]struct { - input []*tfprotov5.DynamicValue - definition function.Definition - expected function.ArgumentsData - expectedDiagnostics diag.Diagnostics + input []*tfprotov5.DynamicValue + definition function.Definition + expected function.ArgumentsData + expectedFuncError *function.FuncError }{ "nil": { input: nil, @@ -49,15 +48,13 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.ArgumentsData{}, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - "Expected function arguments: 2\n"+ - "Given function arguments: 1", - ), - }, + expectedFuncError: function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + "Expected function arguments: 2\n" + + "Given function arguments: 1", + ), }, "mismatched-arguments-too-many-arguments": { input: []*tfprotov5.DynamicValue{ @@ -70,15 +67,13 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.ArgumentsData{}, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - "Expected function arguments: 1\n"+ - "Given function arguments: 2", - ), - }, + expectedFuncError: function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + "Expected function arguments: 1\n" + + "Given function arguments: 2", + ), }, "mismatched-arguments-type": { input: []*tfprotov5.DynamicValue{ @@ -90,15 +85,14 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.ArgumentsData{}, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unable to Convert Function Argument", + expectedFuncError: function.NewArgumentFuncError( + 0, + "Unable to Convert Function Argument: "+ "An unexpected error was encountered when converting the function argument from the protocol type. "+ - "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ - "Please report this to the provider developer:\n\n"+ - "Unable to unmarshal DynamicValue at position 0: error decoding string: msgpack: invalid code=c3 decoding string/bytes length", - ), - }, + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + "Unable to unmarshal DynamicValue at position 0: error decoding string: msgpack: invalid code=c3 decoding string/bytes length", + ), }, "parameters-zero": { input: []*tfprotov5.DynamicValue{}, @@ -147,9 +141,10 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.NewArgumentsData(nil), - expectedDiagnostics: diag.Diagnostics{ - diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), - }, + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: This is an error.", + ), }, "parameters-one-TypeWithValidation-warning": { input: []*tfprotov5.DynamicValue{ @@ -167,9 +162,7 @@ func TestArgumentsData(t *testing.T) { Bool: basetypes.NewBoolValue(true), }, }), - expectedDiagnostics: diag.Diagnostics{ - diag.NewAttributeWarningDiagnostic(path.Empty(), "Warning Diagnostic", "This is a warning."), - }, + // Function error is not generated as diagnostic raised is warning. }, "parameters-one-variadicparameter-zero": { input: []*tfprotov5.DynamicValue{ @@ -418,7 +411,7 @@ func TestArgumentsData(t *testing.T) { t.Errorf("unexpected difference: %s", diff) } - if diff := cmp.Diff(diags, testCase.expectedDiagnostics); diff != "" { + if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { t.Errorf("unexpected diagnostics difference: %s", diff) } }) diff --git a/internal/fromproto5/callfunction.go b/internal/fromproto5/callfunction.go index 4bcd44fe0..ee1225197 100644 --- a/internal/fromproto5/callfunction.go +++ b/internal/fromproto5/callfunction.go @@ -6,15 +6,15 @@ package fromproto5 import ( "context" - "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // CallFunctionRequest returns the *fwserver.CallFunctionRequest // equivalent of a *tfprotov5.CallFunctionRequest. -func CallFunctionRequest(ctx context.Context, proto *tfprotov5.CallFunctionRequest, function function.Function, functionDefinition function.Definition) (*fwserver.CallFunctionRequest, diag.Diagnostics) { +func CallFunctionRequest(ctx context.Context, proto *tfprotov5.CallFunctionRequest, function function.Function, functionDefinition function.Definition) (*fwserver.CallFunctionRequest, *function.FuncError) { if proto == nil { return nil, nil } @@ -24,9 +24,9 @@ func CallFunctionRequest(ctx context.Context, proto *tfprotov5.CallFunctionReque FunctionDefinition: functionDefinition, } - arguments, diags := ArgumentsData(ctx, proto.Arguments, functionDefinition) + arguments, funcError := ArgumentsData(ctx, proto.Arguments, functionDefinition) fw.Arguments = arguments - return fw, diags + return fw, funcError } diff --git a/internal/fromproto5/callfunction_test.go b/internal/fromproto5/callfunction_test.go index b8984cd9c..3cde3f00a 100644 --- a/internal/fromproto5/callfunction_test.go +++ b/internal/fromproto5/callfunction_test.go @@ -8,25 +8,25 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "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/function" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tfprotov5" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestCallFunctionRequest(t *testing.T) { t.Parallel() testCases := map[string]struct { - input *tfprotov5.CallFunctionRequest - function function.Function - functionDefinition function.Definition - expected *fwserver.CallFunctionRequest - expectedDiagnostics diag.Diagnostics + input *tfprotov5.CallFunctionRequest + function function.Function + functionDefinition function.Definition + expected *fwserver.CallFunctionRequest + expectedFuncError *function.FuncError }{ "nil": { input: nil, @@ -92,7 +92,7 @@ func TestCallFunctionRequest(t *testing.T) { t.Errorf("unexpected difference: %s", diff) } - if diff := cmp.Diff(diags, testCase.expectedDiagnostics); diff != "" { + if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { t.Errorf("unexpected diagnostics difference: %s", diff) } }) diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 4cf6de8ad..58fb6e492 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -11,41 +11,37 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-framework/types/validation" ) // ArgumentsData returns the ArgumentsData for a given []*tfprotov6.DynamicValue // and function.Definition. -func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, definition function.Definition) (function.ArgumentsData, diag.Diagnostics) { +func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, definition function.Definition) (function.ArgumentsData, *function.FuncError) { if definition.VariadicParameter == nil && len(arguments) != len(definition.Parameters) { - return function.NewArgumentsData(nil), diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Expected function arguments: %d\n", len(definition.Parameters))+ - fmt.Sprintf("Given function arguments: %d", len(arguments)), - ), - } + return function.NewArgumentsData(nil), function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + fmt.Sprintf("Expected function arguments: %d\n", len(definition.Parameters)) + + fmt.Sprintf("Given function arguments: %d", len(arguments)), + ) } // Expect at least all parameters to have corresponding arguments. Variadic // parameter might have 0 to n arguments, which is why it is not checked in // this case. if len(arguments) < len(definition.Parameters) { - return function.NewArgumentsData(nil), diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Expected minimum function arguments: %d\n", len(definition.Parameters))+ - fmt.Sprintf("Given function arguments: %d", len(arguments)), - ), - } + return function.NewArgumentsData(nil), function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + fmt.Sprintf("Expected minimum function arguments: %d\n", len(definition.Parameters)) + + fmt.Sprintf("Given function arguments: %d", len(arguments)), + ) } if definition.VariadicParameter == nil && len(arguments) == 0 { @@ -55,74 +51,115 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def // Variadic values are collected as a separate tuple to ease developer usage. argumentValues := make([]attr.Value, 0, len(definition.Parameters)) variadicValues := make([]attr.Value, 0, len(arguments)-len(definition.Parameters)) - var diags diag.Diagnostics + var funcError *function.FuncError for position, argument := range arguments { parameter, parameterDiags := definition.Parameter(ctx, position) - diags.Append(parameterDiags...) + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) - if diags.HasError() { - return function.NewArgumentsData(nil), diags + if funcError != nil { + return function.NewArgumentsData(nil), funcError } parameterType := parameter.GetType() + pos := int64(position) + if parameterType == nil { - diags.AddError( - "Unable to Convert Function Argument", - "An unexpected error was encountered when converting the function argument from the protocol type. "+ + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Unable to Convert Function Argument: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ fmt.Sprintf("Parameter type missing at position %d", position), - ) + )) - return function.NewArgumentsData(nil), diags + return function.NewArgumentsData(nil), funcError } tfValue, err := argument.Unmarshal(parameterType.TerraformType(ctx)) if err != nil { - diags.AddError( - "Unable to Convert Function Argument", - "An unexpected error was encountered when converting the function argument from the protocol type. "+ + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Unable to Convert Function Argument: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ fmt.Sprintf("Unable to unmarshal DynamicValue at position %d: %s", position, err), - ) + )) - return function.NewArgumentsData(nil), diags + return function.NewArgumentsData(nil), funcError } attrValue, err := parameterType.ValueFromTerraform(ctx, tfValue) if err != nil { - diags.AddError( - "Unable to Convert Function Argument", - "An unexpected error was encountered when converting the function argument from the protocol type. "+ + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Unable to Convert Function Argument"+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %s", position, err), - ) + fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %stringVal", position, err), + )) - return function.NewArgumentsData(nil), diags + return function.NewArgumentsData(nil), funcError } - // This is intentionally below the attr.Value conversion so it can be - // updated for any new type system validation interfaces. Note that the + // This is intentionally below the conversion of tftypes.Value to attr.Value + // so it can be updated for any new type system validation interfaces. Note that the // original xattr.TypeWithValidation interface must set a path.Path, // which will always be incorrect in the context of functions. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if attrTypeWithValidate, ok := parameterType.(xattr.TypeWithValidate); ok { - logging.FrameworkTrace(ctx, "Parameter type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") - diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path.Empty())...) - logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") - - if diags.HasError() { + switch t := attrValue.(type) { + case validation.ValidateableParameter: + resp := validation.ValidateParameterResponse{} + + logging.FrameworkTrace(ctx, "Parameter value implements ValidateableParameter") + logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateParameter") + + t.ValidateParameter(ctx, + validation.ValidateParameterRequest{ + Position: pos, + }, + &resp, + ) + + logging.FrameworkTrace(ctx, "Called provider defined Value ValidateParameter") + + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + continue } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if t, ok := parameterType.(xattr.TypeWithValidate); ok { + logging.FrameworkTrace(ctx, "Parameter type implements TypeWithValidate") + logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + + diags := t.Validate(ctx, tfValue, path.Empty()) + + logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + + if diags.HasError() { + funcErrFromDiags := function.FuncErrorFromDiags(ctx, diags) + + if funcErrFromDiags != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + funcErrFromDiags.Error())) + } + + continue + } + } } if definition.VariadicParameter != nil && position >= len(definition.Parameters) { @@ -156,14 +193,14 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } variadicValue, variadicValueDiags := basetypes.NewTupleValue(tupleTypes, tupleValues) - diags.Append(variadicValueDiags...) + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, variadicValueDiags)) - if diags.HasError() { - return function.NewArgumentsData(argumentValues), diags + if funcError != nil { + return function.NewArgumentsData(argumentValues), funcError } argumentValues = append(argumentValues, variadicValue) } - return function.NewArgumentsData(argumentValues), diags + return function.NewArgumentsData(argumentValues), funcError } diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index a6ff6ed04..7df28f0d3 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -8,25 +8,24 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "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/function" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" - "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tfprotov6" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestArgumentsData(t *testing.T) { t.Parallel() testCases := map[string]struct { - input []*tfprotov6.DynamicValue - definition function.Definition - expected function.ArgumentsData - expectedDiagnostics diag.Diagnostics + input []*tfprotov6.DynamicValue + definition function.Definition + expected function.ArgumentsData + expectedFuncError *function.FuncError }{ "nil": { input: nil, @@ -49,15 +48,13 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.ArgumentsData{}, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - "Expected function arguments: 2\n"+ - "Given function arguments: 1", - ), - }, + expectedFuncError: function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + "Expected function arguments: 2\n" + + "Given function arguments: 1", + ), }, "mismatched-arguments-too-many-arguments": { input: []*tfprotov6.DynamicValue{ @@ -70,15 +67,13 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.ArgumentsData{}, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unexpected Function Arguments Data", - "The provider received an unexpected number of function arguments from Terraform for the given function definition. "+ - "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n"+ - "Expected function arguments: 1\n"+ - "Given function arguments: 2", - ), - }, + expectedFuncError: function.NewFuncError( + "Unexpected Function Arguments Data: " + + "The provider received an unexpected number of function arguments from Terraform for the given function definition. " + + "This is always an issue in terraform-plugin-framework or Terraform itself and should be reported to the provider developers.\n\n" + + "Expected function arguments: 1\n" + + "Given function arguments: 2", + ), }, "mismatched-arguments-type": { input: []*tfprotov6.DynamicValue{ @@ -90,15 +85,14 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.ArgumentsData{}, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Unable to Convert Function Argument", + expectedFuncError: function.NewArgumentFuncError( + 0, + "Unable to Convert Function Argument: "+ "An unexpected error was encountered when converting the function argument from the protocol type. "+ - "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ - "Please report this to the provider developer:\n\n"+ - "Unable to unmarshal DynamicValue at position 0: error decoding string: msgpack: invalid code=c3 decoding string/bytes length", - ), - }, + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + "Unable to unmarshal DynamicValue at position 0: error decoding string: msgpack: invalid code=c3 decoding string/bytes length", + ), }, "parameters-zero": { input: []*tfprotov6.DynamicValue{}, @@ -147,9 +141,10 @@ func TestArgumentsData(t *testing.T) { }, }, expected: function.NewArgumentsData(nil), - expectedDiagnostics: diag.Diagnostics{ - diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), - }, + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: This is an error.", + ), }, "parameters-one-TypeWithValidation-warning": { input: []*tfprotov6.DynamicValue{ @@ -167,9 +162,7 @@ func TestArgumentsData(t *testing.T) { Bool: basetypes.NewBoolValue(true), }, }), - expectedDiagnostics: diag.Diagnostics{ - diag.NewAttributeWarningDiagnostic(path.Empty(), "Warning Diagnostic", "This is a warning."), - }, + // Function error is not generated as diagnostic raised is warning. }, "parameters-one-variadicparameter-zero": { input: []*tfprotov6.DynamicValue{ @@ -418,7 +411,7 @@ func TestArgumentsData(t *testing.T) { t.Errorf("unexpected difference: %s", diff) } - if diff := cmp.Diff(diags, testCase.expectedDiagnostics); diff != "" { + if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { t.Errorf("unexpected diagnostics difference: %s", diff) } }) diff --git a/internal/fromproto6/callfunction.go b/internal/fromproto6/callfunction.go index 4c1511845..9fb3cb136 100644 --- a/internal/fromproto6/callfunction.go +++ b/internal/fromproto6/callfunction.go @@ -6,15 +6,15 @@ package fromproto6 import ( "context" - "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // CallFunctionRequest returns the *fwserver.CallFunctionRequest // equivalent of a *tfprotov6.CallFunctionRequest. -func CallFunctionRequest(ctx context.Context, proto *tfprotov6.CallFunctionRequest, function function.Function, functionDefinition function.Definition) (*fwserver.CallFunctionRequest, diag.Diagnostics) { +func CallFunctionRequest(ctx context.Context, proto *tfprotov6.CallFunctionRequest, function function.Function, functionDefinition function.Definition) (*fwserver.CallFunctionRequest, *function.FuncError) { if proto == nil { return nil, nil } @@ -24,9 +24,9 @@ func CallFunctionRequest(ctx context.Context, proto *tfprotov6.CallFunctionReque FunctionDefinition: functionDefinition, } - arguments, diags := ArgumentsData(ctx, proto.Arguments, functionDefinition) + arguments, funcError := ArgumentsData(ctx, proto.Arguments, functionDefinition) fw.Arguments = arguments - return fw, diags + return fw, funcError } diff --git a/internal/fromproto6/callfunction_test.go b/internal/fromproto6/callfunction_test.go index c54a111bd..e3bbd30fb 100644 --- a/internal/fromproto6/callfunction_test.go +++ b/internal/fromproto6/callfunction_test.go @@ -8,25 +8,25 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "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/function" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tfprotov6" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestCallFunctionRequest(t *testing.T) { t.Parallel() testCases := map[string]struct { - input *tfprotov6.CallFunctionRequest - function function.Function - functionDefinition function.Definition - expected *fwserver.CallFunctionRequest - expectedDiagnostics diag.Diagnostics + input *tfprotov6.CallFunctionRequest + function function.Function + functionDefinition function.Definition + expected *fwserver.CallFunctionRequest + expectedFuncError *function.FuncError }{ "nil": { input: nil, @@ -92,7 +92,7 @@ func TestCallFunctionRequest(t *testing.T) { t.Errorf("unexpected difference: %s", diff) } - if diff := cmp.Diff(diags, testCase.expectedDiagnostics); diff != "" { + if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { t.Errorf("unexpected diagnostics difference: %s", diff) } }) diff --git a/internal/proto5server/server_callfunction.go b/internal/proto5server/server_callfunction.go index ffd1d6104..010508211 100644 --- a/internal/proto5server/server_callfunction.go +++ b/internal/proto5server/server_callfunction.go @@ -40,9 +40,9 @@ func (s *Server) CallFunction(ctx context.Context, protoReq *tfprotov5.CallFunct return toproto5.CallFunctionResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.CallFunctionRequest(ctx, protoReq, serverFunction, functionDefinition) + fwReq, fwReqError := fromproto5.CallFunctionRequest(ctx, protoReq, serverFunction, functionDefinition) - fwResp.Error = function.ConcatFuncErrors(fwResp.Error, function.FuncErrorFromDiags(ctx, diags)) + fwResp.Error = function.ConcatFuncErrors(fwResp.Error, fwReqError) if fwResp.Error != nil { //nolint:nilerr // error is assigned to fwResp.Error diff --git a/internal/proto6server/server_callfunction.go b/internal/proto6server/server_callfunction.go index eca8255dd..4ca13f530 100644 --- a/internal/proto6server/server_callfunction.go +++ b/internal/proto6server/server_callfunction.go @@ -40,9 +40,9 @@ func (s *Server) CallFunction(ctx context.Context, protoReq *tfprotov6.CallFunct return toproto6.CallFunctionResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.CallFunctionRequest(ctx, protoReq, serverFunction, functionDefinition) + fwReq, fwReqError := fromproto6.CallFunctionRequest(ctx, protoReq, serverFunction, functionDefinition) - fwResp.Error = function.ConcatFuncErrors(fwResp.Error, function.FuncErrorFromDiags(ctx, diags)) + fwResp.Error = function.ConcatFuncErrors(fwResp.Error, fwReqError) if fwResp.Error != nil { //nolint:nilerr // error is assigned to fwResp.Error From b87d7ee3d23d722d5e7b4e0453554755ea015463 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 21 Mar 2024 11:03:17 +0000 Subject: [PATCH 04/62] Modify Data.SetAtPath to use switch statement to handle validation.ValidateableParameter interface --- internal/fwschemadata/data_set_at_path.go | 40 ++++- .../fwschemadata/data_set_at_path_test.go | 61 ++++++- .../testtypes/stringwithvalidateattribute.go | 150 ++++++++++++++++++ 3 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 internal/testing/testtypes/stringwithvalidateattribute.go diff --git a/internal/fwschemadata/data_set_at_path.go b/internal/fwschemadata/data_set_at_path.go index 15b213bfe..894759e8c 100644 --- a/internal/fwschemadata/data_set_at_path.go +++ b/internal/fwschemadata/data_set_at_path.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/reflect" "github.com/hashicorp/terraform-plugin-framework/internal/totftypes" "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types/validation" ) // SetAtPath sets the attribute at `path` using the supplied Go value. @@ -51,6 +52,8 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d return diags } + // MAINTAINER NOTE: The call to reflect.FromValue() checks for whether the type implements + // xattr.TypeWithValidate and calls Validate() if the type assertion succeeds. newVal, newValDiags := reflect.FromValue(ctx, attrType, val, path) diags.Append(newValDiags...) @@ -70,16 +73,41 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d return diags } - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if attrTypeWithValidate, ok := attrType.(xattr.TypeWithValidate); ok { - logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") - diags.Append(attrTypeWithValidate.Validate(ctx, tfVal, path)...) - logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") + switch t := newVal.(type) { + case validation.ValidateableAttribute: + resp := validation.ValidateAttributeResponse{} + + logging.FrameworkTrace(ctx, "Value implements ValidateableAttribute") + logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateAttribute") + + t.ValidateAttribute(ctx, + validation.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + logging.FrameworkTrace(ctx, "Called provider defined Value ValidateAttribute") + + diags.Append(resp.Diagnostics...) if diags.HasError() { return diags } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if attrTypeWithValidate, ok := attrType.(xattr.TypeWithValidate); ok { + logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") + logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + + diags.Append(attrTypeWithValidate.Validate(ctx, tfVal, path)...) + + logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + + if diags.HasError() { + return diags + } + } } transformFunc, transformFuncDiags := d.SetAtPathTransformFunc(ctx, path, tfVal, nil) diff --git a/internal/fwschemadata/data_set_at_path_test.go b/internal/fwschemadata/data_set_at_path_test.go index 2d783785a..1f719ed25 100644 --- a/internal/fwschemadata/data_set_at_path_test.go +++ b/internal/fwschemadata/data_set_at_path_test.go @@ -8,6 +8,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "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" @@ -16,7 +18,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestDataSetAtPath(t *testing.T) { @@ -2611,6 +2612,64 @@ func TestDataSetAtPath(t *testing.T) { testtypes.TestWarningDiagnostic(path.Root("name")), }, }, + "AttrTypeWithValidateAttributeError": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + }, + }, map[string]tftypes.Value{ + "name": tftypes.NewValue(tftypes.String, "originalname"), + }), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "name": testschema.Attribute{ + Type: testtypes.StringTypeWithValidateAttributeError{}, + Required: true, + }, + }, + }, + }, + path: path.Root("name"), + val: "newname", + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + }, + }, map[string]tftypes.Value{ + "name": tftypes.NewValue(tftypes.String, "originalname"), + }), + expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(path.Root("name"))}, + }, + "AttrTypeWithValidateAttributeWarning": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + }, + }, map[string]tftypes.Value{ + "name": tftypes.NewValue(tftypes.String, "originalname"), + }), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "name": testschema.Attribute{ + Type: testtypes.StringTypeWithValidateAttributeWarning{}, + Required: true, + }, + }, + }, + }, + path: path.Root("name"), + val: "newname", + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "name": tftypes.String, + }, + }, map[string]tftypes.Value{ + "name": tftypes.NewValue(tftypes.String, "newname"), + }), + expectedDiags: diag.Diagnostics{testtypes.TestWarningDiagnostic(path.Root("name"))}, + }, } for name, tc := range testCases { diff --git a/internal/testing/testtypes/stringwithvalidateattribute.go b/internal/testing/testtypes/stringwithvalidateattribute.go new file mode 100644 index 000000000..cf435a090 --- /dev/null +++ b/internal/testing/testtypes/stringwithvalidateattribute.go @@ -0,0 +1,150 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types/validation" +) + +type StringTypeWithValidateAttributeError struct { + StringType +} + +func (t StringTypeWithValidateAttributeError) Equal(o attr.Type) bool { + other, ok := o.(StringTypeWithValidateAttributeError) + if !ok { + return false + } + return t == other +} + +func (t StringTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + res, err := t.StringType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newString, ok := res.(String) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", res) + } + + newString.CreatedBy = t + + return StringValueWithValidateAttributeError{ + InternalString: newString, + }, nil +} + +type StringValueWithValidateAttributeError struct { + InternalString String +} + +func (v StringValueWithValidateAttributeError) Type(ctx context.Context) attr.Type { + return v.InternalString.Type(ctx) +} + +func (v StringValueWithValidateAttributeError) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + return v.InternalString.ToTerraformValue(ctx) +} + +func (v StringValueWithValidateAttributeError) Equal(value attr.Value) bool { + other, ok := value.(StringValueWithValidateAttributeError) + + if !ok { + return false + } + + return v == other +} + +func (v StringValueWithValidateAttributeError) IsNull() bool { + return v.InternalString.IsNull() +} + +func (v StringValueWithValidateAttributeError) IsUnknown() bool { + return v.InternalString.IsUnknown() +} + +func (v StringValueWithValidateAttributeError) String() string { + return v.InternalString.String() +} + +func (v StringValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req validation.ValidateAttributeRequest, resp *validation.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) +} + +type StringTypeWithValidateAttributeWarning struct { + StringType +} + +func (t StringTypeWithValidateAttributeWarning) Equal(o attr.Type) bool { + other, ok := o.(StringTypeWithValidateAttributeWarning) + if !ok { + return false + } + return t == other +} + +func (t StringTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + res, err := t.StringType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newString, ok := res.(String) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", res) + } + + newString.CreatedBy = t + + return StringValueWithValidateAttributeWarning{ + InternalString: newString, + }, nil +} + +type StringValueWithValidateAttributeWarning struct { + InternalString String +} + +func (v StringValueWithValidateAttributeWarning) Type(ctx context.Context) attr.Type { + return v.InternalString.Type(ctx) +} + +func (v StringValueWithValidateAttributeWarning) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + return v.InternalString.ToTerraformValue(ctx) +} + +func (v StringValueWithValidateAttributeWarning) Equal(value attr.Value) bool { + other, ok := value.(StringValueWithValidateAttributeWarning) + + if !ok { + return false + } + + return v == other +} + +func (v StringValueWithValidateAttributeWarning) IsNull() bool { + return v.InternalString.IsNull() +} + +func (v StringValueWithValidateAttributeWarning) IsUnknown() bool { + return v.InternalString.IsUnknown() +} + +func (v StringValueWithValidateAttributeWarning) String() string { + return v.InternalString.String() +} + +func (v StringValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req validation.ValidateAttributeRequest, resp *validation.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) +} From cc06028f4ebf2d03f3e4e8840e1a04d3a13194ad Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 21 Mar 2024 11:27:13 +0000 Subject: [PATCH 05/62] Modify Data.SetAtPathTransformFunc to use switch statement to handle validation.ValidateableParameter interface --- internal/fwschemadata/data_set_at_path.go | 48 ++++++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/internal/fwschemadata/data_set_at_path.go b/internal/fwschemadata/data_set_at_path.go index 894759e8c..a55f8e9d4 100644 --- a/internal/fwschemadata/data_set_at_path.go +++ b/internal/fwschemadata/data_set_at_path.go @@ -213,16 +213,52 @@ func (d Data) SetAtPathTransformFunc(ctx context.Context, path path.Path, tfVal return nil, diags } - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if attrTypeWithValidate, ok := parentAttrType.(xattr.TypeWithValidate); ok { - logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") - diags.Append(attrTypeWithValidate.Validate(ctx, parentValue, parentPath)...) - logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") + parentAttrValue, err := parentAttrType.ValueFromTerraform(ctx, parentValue) + + if err != nil { + diags.AddAttributeError( + parentPath, + d.Description.Title()+" Read Error", + "An unexpected error was encountered trying to read an attribute from the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(), + ) + return nil, diags + } + + switch t := parentAttrValue.(type) { + case validation.ValidateableAttribute: + resp := validation.ValidateAttributeResponse{} + + logging.FrameworkTrace(ctx, "Value implements ValidateableAttribute") + logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateAttribute") + + t.ValidateAttribute(ctx, + validation.ValidateAttributeRequest{ + Path: parentPath, + }, + &resp, + ) + + logging.FrameworkTrace(ctx, "Called provider defined Value ValidateAttribute") + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if attrTypeWithValidate, ok := parentAttrType.(xattr.TypeWithValidate); ok { + logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") + logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") + + diags.Append(attrTypeWithValidate.Validate(ctx, parentValue, parentPath)...) + + logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") + + if diags.HasError() { + return nil, diags + } + } } return d.SetAtPathTransformFunc(ctx, parentPath, parentValue, diags) From cf60c85cbc997f413e1d0f4470a39791e3c2d454 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 08:08:12 +0000 Subject: [PATCH 06/62] Temporarily moving ValidateableAttribute interface to xattr package to avoid import cycle --- {types/validation => attr/xattr}/attribute.go | 3 +- internal/fwschemadata/data_set_at_path.go | 13 +- .../fwschemadata/data_set_at_path_test.go | 246 +++++++++++++++++- internal/reflect/primitive.go | 32 ++- .../testtypes/stringwithvalidateattribute.go | 6 +- types/basetypes/list_value_test.go | 9 +- types/basetypes/map_value_test.go | 9 +- types/basetypes/set_value_test.go | 9 +- types/validation/bool_attribute.go | 3 +- types/validation/float64_attribute.go | 3 +- types/validation/int64_attribute.go | 3 +- types/validation/list_attribute.go | 3 +- types/validation/map_attribute.go | 3 +- types/validation/number_attribute.go | 3 +- types/validation/object_attribute.go | 3 +- types/validation/set_attribute.go | 3 +- types/validation/string_attribute.go | 3 +- 17 files changed, 303 insertions(+), 51 deletions(-) rename {types/validation => attr/xattr}/attribute.go (93%) diff --git a/types/validation/attribute.go b/attr/xattr/attribute.go similarity index 93% rename from types/validation/attribute.go rename to attr/xattr/attribute.go index 032f51d1e..84afb0b63 100644 --- a/types/validation/attribute.go +++ b/attr/xattr/attribute.go @@ -1,7 +1,8 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package validation +// TODO: Just putting here for the moment to get rid of import cycle. +package xattr import ( "context" diff --git a/internal/fwschemadata/data_set_at_path.go b/internal/fwschemadata/data_set_at_path.go index a55f8e9d4..66c07ed71 100644 --- a/internal/fwschemadata/data_set_at_path.go +++ b/internal/fwschemadata/data_set_at_path.go @@ -16,7 +16,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/reflect" "github.com/hashicorp/terraform-plugin-framework/internal/totftypes" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework/types/validation" ) // SetAtPath sets the attribute at `path` using the supplied Go value. @@ -74,14 +73,14 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d } switch t := newVal.(type) { - case validation.ValidateableAttribute: - resp := validation.ValidateAttributeResponse{} + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} logging.FrameworkTrace(ctx, "Value implements ValidateableAttribute") logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateAttribute") t.ValidateAttribute(ctx, - validation.ValidateAttributeRequest{ + xattr.ValidateAttributeRequest{ Path: path, }, &resp, @@ -225,14 +224,14 @@ func (d Data) SetAtPathTransformFunc(ctx context.Context, path path.Path, tfVal } switch t := parentAttrValue.(type) { - case validation.ValidateableAttribute: - resp := validation.ValidateAttributeResponse{} + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} logging.FrameworkTrace(ctx, "Value implements ValidateableAttribute") logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateAttribute") t.ValidateAttribute(ctx, - validation.ValidateAttributeRequest{ + xattr.ValidateAttributeRequest{ Path: parentPath, }, &resp, diff --git a/internal/fwschemadata/data_set_at_path_test.go b/internal/fwschemadata/data_set_at_path_test.go index 1f719ed25..b24c9d050 100644 --- a/internal/fwschemadata/data_set_at_path_test.go +++ b/internal/fwschemadata/data_set_at_path_test.go @@ -1931,6 +1931,82 @@ func TestDataSetAtPath(t *testing.T) { testtypes.TestWarningDiagnostic(path.Root("disks").AtListIndex(0).AtName("id")), }, }, + "write-List-Element-AttrTypeWithValidateAttributeWarning": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{}, + }, nil), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "disks": testschema.NestedAttribute{ + NestedObject: testschema.NestedAttributeObject{ + Attributes: map[string]fwschema.Attribute{ + "id": testschema.Attribute{ + Type: testtypes.StringTypeWithValidateAttributeWarning{}, + Required: true, + }, + "delete_with_instance": testschema.Attribute{ + Type: types.BoolType, + Optional: true, + }, + }, + }, + NestingMode: fwschema.NestingModeList, + Optional: true, + Computed: true, + }, + "other": testschema.Attribute{ + Type: types.StringType, + Required: true, + }, + }, + }, + }, + path: path.Root("disks").AtListIndex(0), + val: struct { + ID string `tfsdk:"id"` + DeleteWithInstance bool `tfsdk:"delete_with_instance"` + }{ + ID: "mynewdisk", + DeleteWithInstance: true, + }, + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "disks": tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "delete_with_instance": tftypes.Bool, + }, + }, + }, + "other": tftypes.String, + }, + }, map[string]tftypes.Value{ + "disks": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "delete_with_instance": tftypes.Bool, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "delete_with_instance": tftypes.Bool, + }, + }, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "mynewdisk"), + "delete_with_instance": tftypes.NewValue(tftypes.Bool, true), + }), + }), + "other": tftypes.NewValue(tftypes.String, nil), + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Root("disks").AtListIndex(0).AtName("id")), + }, + }, "write-Map": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ @@ -2113,6 +2189,52 @@ func TestDataSetAtPath(t *testing.T) { testtypes.TestWarningDiagnostic(path.Root("test").AtMapKey("key")), }, }, + "write-Map-Element-AttrTypeWithValidateAttributeWarning": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.Map{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, nil), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "test": testschema.Attribute{ + Type: types.MapType{ + ElemType: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + Required: true, + }, + "other": testschema.Attribute{ + Type: types.StringType, + Required: true, + }, + }, + }, + }, + path: path.Root("test").AtMapKey("key"), + val: "keyvalue", + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.Map{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.String, + }, map[string]tftypes.Value{ + "key": tftypes.NewValue(tftypes.String, "keyvalue"), + }), + "other": tftypes.NewValue(tftypes.String, nil), + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Root("test").AtMapKey("key")), + }, + }, "write-Number": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ @@ -2486,6 +2608,110 @@ func TestDataSetAtPath(t *testing.T) { )).AtName("id")), }, }, + "write-Set-Element-AttrTypeWithValidateAttributeWarning": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "disks": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "delete_with_instance": tftypes.Bool, + }, + }, + }, + "other": tftypes.String, + }, + }, nil), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "disks": testschema.NestedAttribute{ + NestedObject: testschema.NestedAttributeObject{ + Attributes: map[string]fwschema.Attribute{ + "id": testschema.Attribute{ + Type: testtypes.StringTypeWithValidateAttributeWarning{}, + Required: true, + }, + "delete_with_instance": testschema.Attribute{ + Type: types.BoolType, + Optional: true, + }, + }, + }, + NestingMode: fwschema.NestingModeSet, + Optional: true, + Computed: true, + }, + "other": testschema.Attribute{ + Type: types.StringType, + Required: true, + }, + }, + }, + }, + path: path.Root("disks").AtSetValue(types.ObjectValueMust( + map[string]attr.Type{ + "id": types.StringType, + "delete_with_instance": types.BoolType, + }, + map[string]attr.Value{ + "id": types.StringValue("mynewdisk"), + "delete_with_instance": types.BoolValue(true), + }, + )), + val: struct { + ID string `tfsdk:"id"` + DeleteWithInstance bool `tfsdk:"delete_with_instance"` + }{ + ID: "mynewdisk", + DeleteWithInstance: true, + }, + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "disks": tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "delete_with_instance": tftypes.Bool, + }, + }, + }, + "other": tftypes.String, + }, + }, map[string]tftypes.Value{ + "disks": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "delete_with_instance": tftypes.Bool, + }, + }, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "delete_with_instance": tftypes.Bool, + }, + }, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "mynewdisk"), + "delete_with_instance": tftypes.NewValue(tftypes.Bool, true), + }), + }), + "other": tftypes.NewValue(tftypes.String, nil), + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Root("disks").AtSetValue(types.ObjectValueMust( + map[string]attr.Type{ + "id": types.StringType, + "delete_with_instance": types.BoolType, + }, + map[string]attr.Value{ + "id": types.StringValue("mynewdisk"), + "delete_with_instance": types.BoolValue(true), + }, + )).AtName("id")), + }, + }, "write-String": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ @@ -2581,7 +2807,7 @@ func TestDataSetAtPath(t *testing.T) { }), expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(path.Root("name"))}, }, - "AttrTypeWithValidateWarning": { + "AttrTypeWithValidateAttributeError": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ @@ -2593,7 +2819,7 @@ func TestDataSetAtPath(t *testing.T) { Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ "name": testschema.Attribute{ - Type: testtypes.StringTypeWithValidateWarning{}, + Type: testtypes.StringTypeWithValidateAttributeError{}, Required: true, }, }, @@ -2606,13 +2832,11 @@ func TestDataSetAtPath(t *testing.T) { "name": tftypes.String, }, }, map[string]tftypes.Value{ - "name": tftypes.NewValue(tftypes.String, "newname"), + "name": tftypes.NewValue(tftypes.String, "originalname"), }), - expectedDiags: diag.Diagnostics{ - testtypes.TestWarningDiagnostic(path.Root("name")), - }, + expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(path.Root("name"))}, }, - "AttrTypeWithValidateAttributeError": { + "AttrTypeWithValidateWarning": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ @@ -2624,7 +2848,7 @@ func TestDataSetAtPath(t *testing.T) { Schema: testschema.Schema{ Attributes: map[string]fwschema.Attribute{ "name": testschema.Attribute{ - Type: testtypes.StringTypeWithValidateAttributeError{}, + Type: testtypes.StringTypeWithValidateWarning{}, Required: true, }, }, @@ -2637,9 +2861,11 @@ func TestDataSetAtPath(t *testing.T) { "name": tftypes.String, }, }, map[string]tftypes.Value{ - "name": tftypes.NewValue(tftypes.String, "originalname"), + "name": tftypes.NewValue(tftypes.String, "newname"), }), - expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(path.Root("name"))}, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Root("name")), + }, }, "AttrTypeWithValidateAttributeWarning": { data: fwschemadata.Data{ diff --git a/internal/reflect/primitive.go b/internal/reflect/primitive.go index d67daf015..601259d69 100644 --- a/internal/reflect/primitive.go +++ b/internal/reflect/primitive.go @@ -69,20 +69,34 @@ func FromString(ctx context.Context, typ attr.Type, val string, path path.Path) } tfStr := tftypes.NewValue(tftypes.String, val) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfStr, path)...) - - if diags.HasError() { - return nil, diags - } - } - str, err := typ.ValueFromTerraform(ctx, tfStr) if err != nil { return nil, append(diags, valueFromTerraformErrorDiag(err, path)) } + switch t := str.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfStr, path)...) + + if diags.HasError() { + return nil, diags + } + } + } + return str, diags } diff --git a/internal/testing/testtypes/stringwithvalidateattribute.go b/internal/testing/testtypes/stringwithvalidateattribute.go index cf435a090..b37cd18c5 100644 --- a/internal/testing/testtypes/stringwithvalidateattribute.go +++ b/internal/testing/testtypes/stringwithvalidateattribute.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-go/tftypes" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/types/validation" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" ) type StringTypeWithValidateAttributeError struct { @@ -77,7 +77,7 @@ func (v StringValueWithValidateAttributeError) String() string { return v.InternalString.String() } -func (v StringValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req validation.ValidateAttributeRequest, resp *validation.ValidateAttributeResponse) { +func (v StringValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) } @@ -145,6 +145,6 @@ func (v StringValueWithValidateAttributeWarning) String() string { return v.InternalString.String() } -func (v StringValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req validation.ValidateAttributeRequest, resp *validation.ValidateAttributeResponse) { +func (v StringValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) } diff --git a/types/basetypes/list_value_test.go b/types/basetypes/list_value_test.go index a3db64168..cdb706b6b 100644 --- a/types/basetypes/list_value_test.go +++ b/types/basetypes/list_value_test.go @@ -8,10 +8,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "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/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestNewListValue(t *testing.T) { @@ -161,9 +162,9 @@ func TestNewListValueFrom(t *testing.T) { expectedDiags: diag.Diagnostics{ diag.NewAttributeErrorDiagnostic( path.Empty(), - "List Type Validation Error", - "An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ - "expected List value, received tftypes.Value with value: tftypes.String<\"oops\">", + "Value Conversion Error", + "An unexpected error was encountered trying to convert the Terraform value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ + "can't use tftypes.String<\"oops\"> as value of List with ElementType basetypes.StringType, can only use tftypes.String values", ), }, }, diff --git a/types/basetypes/map_value_test.go b/types/basetypes/map_value_test.go index 8bfd3753b..4561b4a6e 100644 --- a/types/basetypes/map_value_test.go +++ b/types/basetypes/map_value_test.go @@ -8,10 +8,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "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/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestNewMapValue(t *testing.T) { @@ -161,9 +162,9 @@ func TestNewMapValueFrom(t *testing.T) { expectedDiags: diag.Diagnostics{ diag.NewAttributeErrorDiagnostic( path.Empty(), - "Map Type Validation Error", - "An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ - "expected Map value, received tftypes.Value with value: tftypes.String<\"oops\">", + "Value Conversion Error", + "An unexpected error was encountered trying to convert the Terraform value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ + "can't use tftypes.String<\"oops\"> as value of MapValue, can only use tftypes.Map values", ), }, }, diff --git a/types/basetypes/set_value_test.go b/types/basetypes/set_value_test.go index 28c0c08a2..e5d63f67e 100644 --- a/types/basetypes/set_value_test.go +++ b/types/basetypes/set_value_test.go @@ -9,10 +9,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "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/path" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestSetElementsAs_stringSlice(t *testing.T) { @@ -444,9 +445,9 @@ func TestNewSetValueFrom(t *testing.T) { expectedDiags: diag.Diagnostics{ diag.NewAttributeErrorDiagnostic( path.Empty(), - "Set Type Validation Error", - "An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ - "expected Set value, received tftypes.Value with value: tftypes.String<\"oops\">", + "Value Conversion Error", + "An unexpected error was encountered trying to convert the Terraform value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ + "can't use tftypes.String<\"oops\"> as value of Set with ElementType basetypes.StringType, can only use tftypes.String values", ), }, }, diff --git a/types/validation/bool_attribute.go b/types/validation/bool_attribute.go index b1e923260..8b3eed64e 100644 --- a/types/validation/bool_attribute.go +++ b/types/validation/bool_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type BoolAttributeWithValidate interface { basetypes.BoolValuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/float64_attribute.go b/types/validation/float64_attribute.go index 2b105090e..c287a63e8 100644 --- a/types/validation/float64_attribute.go +++ b/types/validation/float64_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type Float64AttributeWithValidate interface { basetypes.Float64Valuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/int64_attribute.go b/types/validation/int64_attribute.go index fa62ddfe5..a9e7b38af 100644 --- a/types/validation/int64_attribute.go +++ b/types/validation/int64_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type Int64AttributeWithValidate interface { basetypes.Int64Valuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/list_attribute.go b/types/validation/list_attribute.go index b4dc4ea95..ee05d7730 100644 --- a/types/validation/list_attribute.go +++ b/types/validation/list_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type ListAttributeWithValidate interface { basetypes.ListValuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/map_attribute.go b/types/validation/map_attribute.go index 78b0d1ec9..f295a8919 100644 --- a/types/validation/map_attribute.go +++ b/types/validation/map_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type MapAttributeWithValidate interface { basetypes.MapValuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/number_attribute.go b/types/validation/number_attribute.go index 1752e6157..fa9259742 100644 --- a/types/validation/number_attribute.go +++ b/types/validation/number_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type NumberAttributeWithValidate interface { basetypes.NumberValuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/object_attribute.go b/types/validation/object_attribute.go index 23f389b4f..478b4680d 100644 --- a/types/validation/object_attribute.go +++ b/types/validation/object_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type ObjectAttributeWithValidate interface { basetypes.ObjectValuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/set_attribute.go b/types/validation/set_attribute.go index 8b636ab65..c36c18e42 100644 --- a/types/validation/set_attribute.go +++ b/types/validation/set_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type SetAttributeWithValidate interface { basetypes.SetValuable - ValidateableAttribute + xattr.ValidateableAttribute } diff --git a/types/validation/string_attribute.go b/types/validation/string_attribute.go index 48b987bc1..b02e2ada9 100644 --- a/types/validation/string_attribute.go +++ b/types/validation/string_attribute.go @@ -4,6 +4,7 @@ package validation import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -13,5 +14,5 @@ import ( type StringAttributeWithValidate interface { basetypes.StringValuable - ValidateableAttribute + xattr.ValidateableAttribute } From 995b96c5dd7f7aa92722dd8dc757d2d11a4874f9 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 08:46:28 +0000 Subject: [PATCH 07/62] Adding test coverage for list, map and set for SetAtPathTransformFunc --- .../fwschemadata/data_set_at_path_test.go | 146 ++++++++++++++++++ .../testtypes/listwithvalidateattribute.go | 75 +++++++++ .../testtypes/mapwithvalidateattribute.go | 75 +++++++++ .../testtypes/setwithvalidateattribute.go | 75 +++++++++ .../testtypes/stringwithvalidateattribute.go | 16 +- 5 files changed, 381 insertions(+), 6 deletions(-) create mode 100644 internal/testing/testtypes/listwithvalidateattribute.go create mode 100644 internal/testing/testtypes/mapwithvalidateattribute.go create mode 100644 internal/testing/testtypes/setwithvalidateattribute.go diff --git a/internal/fwschemadata/data_set_at_path_test.go b/internal/fwschemadata/data_set_at_path_test.go index b24c9d050..13d7e878a 100644 --- a/internal/fwschemadata/data_set_at_path_test.go +++ b/internal/fwschemadata/data_set_at_path_test.go @@ -1701,6 +1701,55 @@ func TestDataSetAtPath(t *testing.T) { testtypes.TestWarningDiagnostic(path.Root("test")), }, }, + "write-List-AttrTypeWithValidateAttributeWarning-Element": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.List{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, nil), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "test": testschema.Attribute{ + Type: testtypes.ListTypeWithValidateAttributeWarning{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + Optional: true, + Computed: true, + }, + "other": testschema.Attribute{ + Type: types.StringType, + Required: true, + }, + }, + }, + }, + path: path.Root("test").AtListIndex(0), + val: "testvalue", + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.List{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.List{ + ElementType: tftypes.String, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.String, "testvalue"), + }), + "other": tftypes.NewValue(tftypes.String, nil), + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Root("test")), + }, + }, "write-List-Element": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ @@ -2100,6 +2149,54 @@ func TestDataSetAtPath(t *testing.T) { testtypes.TestWarningDiagnostic(path.Root("test")), }, }, + "write-Map-AttrTypeWithValidateAttributeWarning-Element": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.Map{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, nil), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "test": testschema.Attribute{ + Type: testtypes.MapTypeWithValidateAttributeWarning{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + Required: true, + }, + "other": testschema.Attribute{ + Type: types.StringType, + Required: true, + }, + }, + }, + }, + path: path.Root("test").AtMapKey("key"), + val: "keyvalue", + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.Map{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.Map{ + ElementType: tftypes.String, + }, map[string]tftypes.Value{ + "key": tftypes.NewValue(tftypes.String, "keyvalue"), + }), + "other": tftypes.NewValue(tftypes.String, nil), + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Root("test")), + }, + }, "write-Map-Element": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ @@ -2504,6 +2601,55 @@ func TestDataSetAtPath(t *testing.T) { testtypes.TestWarningDiagnostic(path.Root("test")), }, }, + "write-Set-AttrTypeWithValidateAttributeWarning-Element": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.Set{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, nil), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "test": testschema.Attribute{ + Type: testtypes.SetTypeWithValidateAttributeWarning{ + SetType: types.SetType{ + ElemType: types.StringType, + }, + }, + Optional: true, + Computed: true, + }, + "other": testschema.Attribute{ + Type: types.StringType, + Required: true, + }, + }, + }, + }, + path: path.Root("test").AtSetValue(types.StringValue("testvalue")), + val: "testvalue", + expected: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.Set{ + ElementType: tftypes.String, + }, + "other": tftypes.String, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.Set{ + ElementType: tftypes.String, + }, []tftypes.Value{ + tftypes.NewValue(tftypes.String, "testvalue"), + }), + "other": tftypes.NewValue(tftypes.String, nil), + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Root("test")), + }, + }, "write-Set-Element-AttrTypeWithValidateWarning": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ diff --git a/internal/testing/testtypes/listwithvalidateattribute.go b/internal/testing/testtypes/listwithvalidateattribute.go new file mode 100644 index 000000000..f0f95a4e7 --- /dev/null +++ b/internal/testing/testtypes/listwithvalidateattribute.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ListTypeWithValidateAttributeError struct { + types.ListType +} + +func (t ListTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.ListType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + list, ok := val.(types.List) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.List", val) + } + + return ListValueWithValidateAttributeError{ + list, + }, nil +} + +var _ xattr.ValidateableAttribute = ListValueWithValidateAttributeError{} + +type ListValueWithValidateAttributeError struct { + types.List +} + +func (v ListValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) +} + +type ListTypeWithValidateAttributeWarning struct { + types.ListType +} + +func (t ListTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.ListType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + list, ok := val.(types.List) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.List", val) + } + + return ListValueWithValidateAttributeWarning{ + list, + }, nil +} + +var _ xattr.ValidateableAttribute = ListValueWithValidateAttributeWarning{} + +type ListValueWithValidateAttributeWarning struct { + types.List +} + +func (v ListValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) +} diff --git a/internal/testing/testtypes/mapwithvalidateattribute.go b/internal/testing/testtypes/mapwithvalidateattribute.go new file mode 100644 index 000000000..b33076873 --- /dev/null +++ b/internal/testing/testtypes/mapwithvalidateattribute.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type MapTypeWithValidateAttributeError struct { + types.MapType +} + +func (t MapTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.MapType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + m, ok := val.(types.Map) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.Map", val) + } + + return MapValueWithValidateAttributeError{ + m, + }, nil +} + +var _ xattr.ValidateableAttribute = MapValueWithValidateAttributeError{} + +type MapValueWithValidateAttributeError struct { + types.Map +} + +func (v MapValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) +} + +type MapTypeWithValidateAttributeWarning struct { + types.MapType +} + +func (t MapTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.MapType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + m, ok := val.(types.Map) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.Map", val) + } + + return MapValueWithValidateAttributeWarning{ + m, + }, nil +} + +var _ xattr.ValidateableAttribute = MapValueWithValidateAttributeWarning{} + +type MapValueWithValidateAttributeWarning struct { + types.Map +} + +func (v MapValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) +} diff --git a/internal/testing/testtypes/setwithvalidateattribute.go b/internal/testing/testtypes/setwithvalidateattribute.go new file mode 100644 index 000000000..d1ee86cc0 --- /dev/null +++ b/internal/testing/testtypes/setwithvalidateattribute.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type SetTypeWithValidateAttributeError struct { + types.SetType +} + +func (t SetTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.SetType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + set, ok := val.(types.Set) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.Set", val) + } + + return SetValueWithValidateAttributeError{ + set, + }, nil +} + +var _ xattr.ValidateableAttribute = SetValueWithValidateAttributeError{} + +type SetValueWithValidateAttributeError struct { + types.Set +} + +func (v SetValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) +} + +type SetTypeWithValidateAttributeWarning struct { + types.SetType +} + +func (t SetTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.SetType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + set, ok := val.(types.Set) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.Set", val) + } + + return SetValueWithValidateAttributeWarning{ + set, + }, nil +} + +var _ xattr.ValidateableAttribute = SetValueWithValidateAttributeWarning{} + +type SetValueWithValidateAttributeWarning struct { + types.Set +} + +func (v SetValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) +} diff --git a/internal/testing/testtypes/stringwithvalidateattribute.go b/internal/testing/testtypes/stringwithvalidateattribute.go index b37cd18c5..cb6440db0 100644 --- a/internal/testing/testtypes/stringwithvalidateattribute.go +++ b/internal/testing/testtypes/stringwithvalidateattribute.go @@ -26,14 +26,14 @@ func (t StringTypeWithValidateAttributeError) Equal(o attr.Type) bool { } func (t StringTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { - res, err := t.StringType.ValueFromTerraform(ctx, in) + val, err := t.StringType.ValueFromTerraform(ctx, in) if err != nil { return nil, err } - newString, ok := res.(String) + newString, ok := val.(String) if !ok { - return nil, fmt.Errorf("unexpected value type of %T", res) + return nil, fmt.Errorf("unexpected value type of %T", val) } newString.CreatedBy = t @@ -43,6 +43,8 @@ func (t StringTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Con }, nil } +var _ xattr.ValidateableAttribute = StringValueWithValidateAttributeError{} + type StringValueWithValidateAttributeError struct { InternalString String } @@ -94,14 +96,14 @@ func (t StringTypeWithValidateAttributeWarning) Equal(o attr.Type) bool { } func (t StringTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { - res, err := t.StringType.ValueFromTerraform(ctx, in) + val, err := t.StringType.ValueFromTerraform(ctx, in) if err != nil { return nil, err } - newString, ok := res.(String) + newString, ok := val.(String) if !ok { - return nil, fmt.Errorf("unexpected value type of %T", res) + return nil, fmt.Errorf("unexpected value type of %T", val) } newString.CreatedBy = t @@ -111,6 +113,8 @@ func (t StringTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.C }, nil } +var _ xattr.ValidateableAttribute = StringValueWithValidateAttributeWarning{} + type StringValueWithValidateAttributeWarning struct { InternalString String } From fe30c12f1be61874fc9628a89ed6c1987ea088d2 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 09:12:52 +0000 Subject: [PATCH 08/62] Adding test coverage for bool ValidateableParameter for fromproto5/6 ArgumentsData() --- internal/fromproto5/arguments_data_test.go | 17 ++++++ internal/fromproto6/arguments_data_test.go | 17 ++++++ .../testtypes/boolwithvalidateparameter.go | 55 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 internal/testing/testtypes/boolwithvalidateparameter.go diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 649bbb96a..b23d231d9 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -146,6 +146,23 @@ func TestArgumentsData(t *testing.T) { "Error Diagnostic: This is an error.", ), }, + "parameters-one-TypeWithParameterValidation-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateParameterError{}, + }, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "This is a function error", + ), + }, "parameters-one-TypeWithValidation-warning": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index 7df28f0d3..fcca1de63 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -146,6 +146,23 @@ func TestArgumentsData(t *testing.T) { "Error Diagnostic: This is an error.", ), }, + "parameters-one-TypeWithParameterValidation-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateParameterError{}, + }, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "This is a function error", + ), + }, "parameters-one-TypeWithValidation-warning": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), diff --git a/internal/testing/testtypes/boolwithvalidateparameter.go b/internal/testing/testtypes/boolwithvalidateparameter.go new file mode 100644 index 000000000..3bb07894f --- /dev/null +++ b/internal/testing/testtypes/boolwithvalidateparameter.go @@ -0,0 +1,55 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types/validation" +) + +type BoolTypeWithValidateParameterError struct { + BoolType +} + +func (t BoolTypeWithValidateParameterError) Equal(o attr.Type) bool { + other, ok := o.(BoolTypeWithValidateParameterError) + if !ok { + return false + } + return t == other +} + +func (t BoolTypeWithValidateParameterError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.BoolType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newBool, ok := val.(Bool) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", val) + } + + newBool.CreatedBy = t + + return BoolValueWithValidateParameterError{ + newBool, + }, nil +} + +var _ validation.ValidateableParameter = BoolValueWithValidateParameterError{} + +type BoolValueWithValidateParameterError struct { + Bool +} + +func (v BoolValueWithValidateParameterError) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { + resp.Error = function.NewArgumentFuncError(req.Position, "This is a function error") +} From 7328488d27beec1ba69815c192c3655981be5b54 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 09:58:43 +0000 Subject: [PATCH 09/62] Adding switch statement for ValidateableAttribute to fwschemadata Data.ValueAtPaath() --- internal/fwschemadata/data_value.go | 49 +++++++++++---- internal/fwschemadata/data_value_test.go | 59 ++++++++++++++++++- .../fwserver/attribute_validation_test.go | 6 +- .../fwserver/schema_plan_modification_test.go | 19 +++--- 4 files changed, 107 insertions(+), 26 deletions(-) diff --git a/internal/fwschemadata/data_value.go b/internal/fwschemadata/data_value.go index f74c52f83..79e148626 100644 --- a/internal/fwschemadata/data_value.go +++ b/internal/fwschemadata/data_value.go @@ -77,18 +77,6 @@ func (d Data) ValueAtPath(ctx context.Context, schemaPath path.Path) (attr.Value // If found, convert this value to an unknown value. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186 - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if attrTypeWithValidate, ok := attrType.(xattr.TypeWithValidate); ok { - logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") - logging.FrameworkTrace(ctx, "Calling provider defined Type ValidateAttribute") - diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, schemaPath)...) - logging.FrameworkTrace(ctx, "Called provider defined Type ValidateAttribute") - - if diags.HasError() { - return nil, diags - } - } - attrValue, err := attrType.ValueFromTerraform(ctx, tfValue) if err != nil { @@ -101,5 +89,42 @@ func (d Data) ValueAtPath(ctx context.Context, schemaPath path.Path) (attr.Value return nil, diags } + switch t := attrValue.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + logging.FrameworkTrace(ctx, "Value implements ValidateableAttribute") + logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateAttribute") + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: schemaPath, + }, + &resp, + ) + + logging.FrameworkTrace(ctx, "Called provider defined Value ValidateAttribute") + + diags.Append(resp.Diagnostics...) + + if diags.HasError() { + return nil, diags + } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if attrTypeWithValidate, ok := attrType.(xattr.TypeWithValidate); ok { + logging.FrameworkTrace(ctx, "Type implements TypeWithValidate") + logging.FrameworkTrace(ctx, "Calling provider defined Type Validate") + + diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, schemaPath)...) + + logging.FrameworkTrace(ctx, "Called provider defined Type Validate") + + if diags.HasError() { + return nil, diags + } + } + } + return attrValue, diags } diff --git a/internal/fwschemadata/data_value_test.go b/internal/fwschemadata/data_value_test.go index 0bc1dfeed..b13b7e961 100644 --- a/internal/fwschemadata/data_value_test.go +++ b/internal/fwschemadata/data_value_test.go @@ -8,6 +8,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "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" @@ -16,7 +18,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestDataValueAtPath(t *testing.T) { @@ -2058,6 +2059,34 @@ func TestDataValueAtPath(t *testing.T) { expected: nil, expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(path.Root("test"))}, }, + "AttrTypeWithValidateAttributeError": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.String, + "other": tftypes.Bool, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.String, "value"), + "other": tftypes.NewValue(tftypes.Bool, nil), + }), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "test": testschema.Attribute{ + Type: testtypes.StringTypeWithValidateAttributeError{}, + Required: true, + }, + "other": testschema.Attribute{ + Type: types.BoolType, + Optional: true, + }, + }, + }, + }, + path: path.Root("test"), + expected: nil, + expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(path.Root("test"))}, + }, "AttrTypeWithValidateWarning": { data: fwschemadata.Data{ TerraformValue: tftypes.NewValue(tftypes.Object{ @@ -2086,6 +2115,34 @@ func TestDataValueAtPath(t *testing.T) { expected: testtypes.String{InternalString: types.StringValue("value"), CreatedBy: testtypes.StringTypeWithValidateWarning{}}, expectedDiags: diag.Diagnostics{testtypes.TestWarningDiagnostic(path.Root("test"))}, }, + "AttrTypeWithValidateAttributeWarning": { + data: fwschemadata.Data{ + TerraformValue: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.String, + "other": tftypes.Bool, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.String, "value"), + "other": tftypes.NewValue(tftypes.Bool, nil), + }), + Schema: testschema.Schema{ + Attributes: map[string]fwschema.Attribute{ + "test": testschema.Attribute{ + Type: testtypes.StringTypeWithValidateAttributeWarning{}, + Required: true, + }, + "other": testschema.Attribute{ + Type: types.BoolType, + Optional: true, + }, + }, + }, + }, + path: path.Root("test"), + expected: testtypes.StringValueWithValidateAttributeWarning{InternalString: testtypes.String{InternalString: types.StringValue("value"), CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}}}, + expectedDiags: diag.Diagnostics{testtypes.TestWarningDiagnostic(path.Root("test"))}, + }, } for name, tc := range testCases { diff --git a/internal/fwserver/attribute_validation_test.go b/internal/fwserver/attribute_validation_test.go index 62ff54f6d..c649f63e2 100644 --- a/internal/fwserver/attribute_validation_test.go +++ b/internal/fwserver/attribute_validation_test.go @@ -87,9 +87,9 @@ func TestAttributeValidate(t *testing.T) { Diagnostics: diag.Diagnostics{ diag.NewAttributeErrorDiagnostic( path.Root("test"), - "List Type Validation Error", - "An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ - "expected List value, received tftypes.Value with value: tftypes.String<\"testvalue\">", + "Configuration Read Error", + "An unexpected error was encountered trying to convert an attribute value from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ + "Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType basetypes.StringType, can only use tftypes.String values", ), }, }, diff --git a/internal/fwserver/schema_plan_modification_test.go b/internal/fwserver/schema_plan_modification_test.go index de022a196..3e00223ec 100644 --- a/internal/fwserver/schema_plan_modification_test.go +++ b/internal/fwserver/schema_plan_modification_test.go @@ -94,9 +94,9 @@ func TestSchemaModifyPlan(t *testing.T) { Diagnostics: diag.Diagnostics{ diag.NewAttributeErrorDiagnostic( path.Root("test"), - "List Type Validation Error", - "An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ - "expected List value, received tftypes.Value with value: tftypes.String<\"testvalue\">", + "Configuration Read Error", + "An unexpected error was encountered trying to convert an attribute value from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ + "Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType basetypes.StringType, can only use tftypes.String values", ), }, Plan: tfsdk.Plan{ @@ -176,10 +176,9 @@ func TestSchemaModifyPlan(t *testing.T) { Diagnostics: diag.Diagnostics{ diag.NewAttributeErrorDiagnostic( path.Root("test"), - "List Type Validation Error", - "An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ - "expected List value, received tftypes.Value with value: tftypes.String<\"testvalue\">", - ), + "Plan Read Error", + "An unexpected error was encountered trying to convert an attribute value from the plan. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ + "Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType basetypes.StringType, can only use tftypes.String values"), }, Plan: tfsdk.Plan{ Raw: tftypes.NewValue(tftypes.Object{ @@ -258,9 +257,9 @@ func TestSchemaModifyPlan(t *testing.T) { Diagnostics: diag.Diagnostics{ diag.NewAttributeErrorDiagnostic( path.Root("test"), - "List Type Validation Error", - "An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ - "expected List value, received tftypes.Value with value: tftypes.String<\"testvalue\">", + "State Read Error", + "An unexpected error was encountered trying to convert an attribute value from the state. This is always an error in the provider. Please report the following to the provider developer:\n\n"+ + "Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType basetypes.StringType, can only use tftypes.String values", ), }, Plan: tfsdk.Plan{ From b27c7fa69c1e511dfc473d899704346862c8d117 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 12:21:05 +0000 Subject: [PATCH 10/62] Adding switch statements to internal/reflect/interfaces to handle ValidateableAttribute assertions --- internal/reflect/interfaces.go | 230 ++++++++++++++---- internal/reflect/interfaces_test.go | 147 ++++++++++- .../testtypes/boolwithvalidateattribute.go | 64 +++++ 3 files changed, 388 insertions(+), 53 deletions(-) create mode 100644 internal/testing/testtypes/boolwithvalidateattribute.go diff --git a/internal/reflect/interfaces.go b/internal/reflect/interfaces.go index e458f95e3..1811a1b8e 100644 --- a/internal/reflect/interfaces.go +++ b/internal/reflect/interfaces.go @@ -75,19 +75,38 @@ func FromUnknownable(ctx context.Context, typ attr.Type, val Unknownable, path p if val.GetUnknown(ctx) { tfVal := tftypes.NewValue(typ.TerraformType(ctx), tftypes.UnknownValue) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + res, err := typ.ValueFromTerraform(ctx, tfVal) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := res.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - res, err := typ.ValueFromTerraform(ctx, tfVal) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } + return res, nil } err := tftypes.ValidateValue(typ.TerraformType(ctx), val.GetValue(ctx)) @@ -97,19 +116,38 @@ func FromUnknownable(ctx context.Context, typ attr.Type, val Unknownable, path p tfVal := tftypes.NewValue(typ.TerraformType(ctx), val.GetValue(ctx)) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + res, err := typ.ValueFromTerraform(ctx, tfVal) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := res.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - res, err := typ.ValueFromTerraform(ctx, tfVal) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } + return res, nil } @@ -171,19 +209,38 @@ func FromNullable(ctx context.Context, typ attr.Type, val Nullable, path path.Pa if val.GetNull(ctx) { tfVal := tftypes.NewValue(typ.TerraformType(ctx), nil) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + res, err := typ.ValueFromTerraform(ctx, tfVal) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := res.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - res, err := typ.ValueFromTerraform(ctx, tfVal) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } + return res, nil } err := tftypes.ValidateValue(typ.TerraformType(ctx), val.GetValue(ctx)) @@ -193,19 +250,38 @@ func FromNullable(ctx context.Context, typ attr.Type, val Nullable, path path.Pa tfVal := tftypes.NewValue(typ.TerraformType(ctx), val.GetValue(ctx)) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + res, err := typ.ValueFromTerraform(ctx, tfVal) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := res.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - res, err := typ.ValueFromTerraform(ctx, tfVal) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } + return res, diags } @@ -265,19 +341,38 @@ func FromValueCreator(ctx context.Context, typ attr.Type, val tftypes.ValueCreat } tfVal := tftypes.NewValue(typ.TerraformType(ctx), raw) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + res, err := typ.ValueFromTerraform(ctx, tfVal) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := res.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - res, err := typ.ValueFromTerraform(ctx, tfVal) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } + return res, diags } @@ -289,19 +384,38 @@ func FromValueCreator(ctx context.Context, typ attr.Type, val tftypes.ValueCreat func NewAttributeValue(ctx context.Context, typ attr.Type, val tftypes.Value, target reflect.Value, opts Options, path path.Path) (reflect.Value, diag.Diagnostics) { var diags diag.Diagnostics - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, val, path)...) + res, err := typ.ValueFromTerraform(ctx, val) + if err != nil { + return target, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := res.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return target, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, val, path)...) - res, err := typ.ValueFromTerraform(ctx, val) - if err != nil { - return target, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return target, diags + } + } } + if reflect.TypeOf(res) != target.Type() { diags.Append(diag.WithPath(path, DiagNewAttributeValueIntoWrongType{ ValType: reflect.TypeOf(res), @@ -341,18 +455,36 @@ func FromAttributeValue(ctx context.Context, typ attr.Type, val attr.Value, path return nil, diags } - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - tfVal, err := val.ToTerraformValue(ctx) - if err != nil { - return val, append(diags, toTerraformValueErrorDiag(err, path)) - } + switch t := val.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return val, diags } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + tfVal, err := val.ToTerraformValue(ctx) + if err != nil { + return val, append(diags, toTerraformValueErrorDiag(err, path)) + } + + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + + if diags.HasError() { + return val, diags + } + } } return val, diags diff --git a/internal/reflect/interfaces_test.go b/internal/reflect/interfaces_test.go index 514acd077..9dc176d93 100644 --- a/internal/reflect/interfaces_test.go +++ b/internal/reflect/interfaces_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" refl "github.com/hashicorp/terraform-plugin-framework/internal/reflect" @@ -289,22 +290,61 @@ func TestFromUnknownable(t *testing.T) { t.Parallel() testCases := map[string]struct { + typ attr.Type val refl.Unknownable expected attr.Value expectedDiags diag.Diagnostics }{ "unknown": { + typ: types.StringType, val: &unknownableString{ Unknown: true, }, expected: types.StringUnknown(), }, + "unknown-validate-error": { + typ: testtypes.StringTypeWithValidateError{}, + val: &unknownableString{ + Unknown: true, + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, + "unknown-validate-attribute-error": { + typ: testtypes.StringTypeWithValidateAttributeError{}, + val: &unknownableString{ + Unknown: true, + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, "value": { + typ: types.StringType, val: &unknownableString{ String: "hello, world", }, expected: types.StringValue("hello, world"), }, + "value-validate-error": { + typ: testtypes.StringTypeWithValidateError{}, + val: &unknownableString{ + String: "hello, world", + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, + "value-validate-attribute-error": { + typ: testtypes.StringTypeWithValidateAttributeError{}, + val: &unknownableString{ + String: "hello, world", + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, } for name, tc := range testCases { @@ -312,7 +352,7 @@ func TestFromUnknownable(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := refl.FromUnknownable(context.Background(), types.StringType, tc.val, path.Empty()) + got, diags := refl.FromUnknownable(context.Background(), tc.typ, tc.val, path.Empty()) if diff := cmp.Diff(diags, tc.expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -390,22 +430,61 @@ func TestFromNullable(t *testing.T) { t.Parallel() testCases := map[string]struct { + typ attr.Type val refl.Nullable expected attr.Value expectedDiags diag.Diagnostics }{ "null": { + typ: types.StringType, val: &nullableString{ Null: true, }, expected: types.StringNull(), }, + "null-validate-error": { + typ: testtypes.StringTypeWithValidateError{}, + val: &nullableString{ + Null: true, + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, + "null-validate-attribute-error": { + typ: testtypes.StringTypeWithValidateAttributeError{}, + val: &nullableString{ + Null: true, + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, "value": { + typ: types.StringType, val: &nullableString{ String: "hello, world", }, expected: types.StringValue("hello, world"), }, + "value-validate-error": { + typ: testtypes.StringTypeWithValidateError{}, + val: &nullableString{ + String: "hello, world", + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, + "value-validate-attribute-error": { + typ: testtypes.StringTypeWithValidateError{}, + val: &nullableString{ + String: "hello, world", + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, } for name, tc := range testCases { @@ -413,7 +492,7 @@ func TestFromNullable(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := refl.FromNullable(context.Background(), types.StringType, tc.val, path.Empty()) + got, diags := refl.FromNullable(context.Background(), tc.typ, tc.val, path.Empty()) if diff := cmp.Diff(diags, tc.expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -430,26 +509,44 @@ func TestNewAttributeValue(t *testing.T) { t.Parallel() testCases := map[string]struct { + typ attr.Type val tftypes.Value target reflect.Value expected attr.Value expectedDiags diag.Diagnostics }{ "unknown": { + typ: types.StringType, val: tftypes.NewValue(tftypes.String, tftypes.UnknownValue), target: reflect.ValueOf(types.String{}), expected: types.StringUnknown(), }, "null": { + typ: types.StringType, val: tftypes.NewValue(tftypes.String, nil), target: reflect.ValueOf(types.String{}), expected: types.StringNull(), }, "value": { + typ: types.StringType, val: tftypes.NewValue(tftypes.String, "hello"), target: reflect.ValueOf(types.String{}), expected: types.StringValue("hello"), }, + "validate-error": { + typ: testtypes.StringTypeWithValidateError{}, + val: tftypes.NewValue(tftypes.String, "hello"), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, + "validate-attribute-error": { + typ: testtypes.StringTypeWithValidateAttributeError{}, + val: tftypes.NewValue(tftypes.String, "hello"), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, } for name, tc := range testCases { @@ -457,7 +554,7 @@ func TestNewAttributeValue(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - res, diags := refl.NewAttributeValue(context.Background(), types.StringType, tc.val, tc.target, refl.Options{}, path.Empty()) + res, diags := refl.NewAttributeValue(context.Background(), tc.typ, tc.val, tc.target, refl.Options{}, path.Empty()) if diff := cmp.Diff(diags, tc.expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -507,6 +604,26 @@ func TestFromAttributeValue(t *testing.T) { val: types.BoolNull(), expected: types.BoolNull(), }, + "BoolTypable-BoolValue-ValidateError": { + typ: testtypes.BoolTypeWithValidateError{}, + val: types.BoolNull(), + expected: types.BoolNull(), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Root("test"), "Error Diagnostic", "This is an error."), + }, + }, + "BoolTypable-BoolValue-ValidateAttributeError": { + typ: testtypes.BoolType{}, + val: testtypes.BoolValueWithValidateAttributeError{ + Bool: testtypes.Bool{ + CreatedBy: testtypes.BoolTypeWithValidateAttributeError{}, + }, + }, + expected: testtypes.BoolValueWithValidateAttributeError{Bool: testtypes.Bool{CreatedBy: testtypes.BoolTypeWithValidateAttributeError{}}}, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Root("test"), "Error Diagnostic", "This is an error."), + }, + }, "Float64Type-Float64Value": { typ: types.Float64Type, val: types.Float64Null(), @@ -812,28 +929,50 @@ func TestFromValueCreator(t *testing.T) { t.Parallel() testCases := map[string]struct { + typ attr.Type vc *valueCreator expected attr.Value expectedDiags diag.Diagnostics }{ "null": { + typ: types.StringType, vc: &valueCreator{ null: true, }, expected: types.StringNull(), }, "unknown": { + typ: types.StringType, vc: &valueCreator{ unknown: true, }, expected: types.StringUnknown(), }, "value": { + typ: types.StringType, vc: &valueCreator{ value: "hello, world", }, expected: types.StringValue("hello, world"), }, + "validate-error": { + typ: testtypes.StringTypeWithValidateError{}, + vc: &valueCreator{ + value: "hello, world", + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, + "validate-attribute-error": { + typ: testtypes.StringTypeWithValidateAttributeError{}, + vc: &valueCreator{ + value: "hello, world", + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic(path.Empty(), "Error Diagnostic", "This is an error."), + }, + }, } for name, tc := range testCases { @@ -841,7 +980,7 @@ func TestFromValueCreator(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := refl.FromValueCreator(context.Background(), types.StringType, tc.vc, path.Empty()) + got, diags := refl.FromValueCreator(context.Background(), tc.typ, tc.vc, path.Empty()) if diff := cmp.Diff(diags, tc.expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) diff --git a/internal/testing/testtypes/boolwithvalidateattribute.go b/internal/testing/testtypes/boolwithvalidateattribute.go new file mode 100644 index 000000000..7e9b4b248 --- /dev/null +++ b/internal/testing/testtypes/boolwithvalidateattribute.go @@ -0,0 +1,64 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" +) + +type BoolTypeWithValidateAttributeError struct { + BoolType +} + +func (t BoolTypeWithValidateAttributeError) Equal(o attr.Type) bool { + other, ok := o.(BoolTypeWithValidateAttributeError) + if !ok { + return false + } + return t == other +} + +func (t BoolTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.BoolType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newBool, ok := val.(Bool) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", val) + } + + newBool.CreatedBy = t + + return BoolValueWithValidateAttributeError{ + newBool, + }, nil +} + +var _ xattr.ValidateableAttribute = BoolValueWithValidateAttributeError{} + +type BoolValueWithValidateAttributeError struct { + Bool +} + +func (v BoolValueWithValidateAttributeError) Equal(o attr.Value) bool { + ob, ok := o.(BoolValueWithValidateAttributeError) + + if !ok { + return false + } + + return v.Bool.Equal(ob.Bool) +} + +func (v BoolValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) +} From a8103f66293f0b7fc8bc31e4d72f5abf3716d88d Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 12:27:34 +0000 Subject: [PATCH 11/62] Fix usage of incorrect test type --- internal/reflect/interfaces_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/reflect/interfaces_test.go b/internal/reflect/interfaces_test.go index 9dc176d93..f3e197b78 100644 --- a/internal/reflect/interfaces_test.go +++ b/internal/reflect/interfaces_test.go @@ -477,7 +477,7 @@ func TestFromNullable(t *testing.T) { }, }, "value-validate-attribute-error": { - typ: testtypes.StringTypeWithValidateError{}, + typ: testtypes.StringTypeWithValidateAttributeError{}, val: &nullableString{ String: "hello, world", }, From 06a5b8767406be764ef42d677677cdb319d6964a Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 13:21:03 +0000 Subject: [PATCH 12/62] Adding switch statements to internal/reflect/primitive to handle ValidateableAttribute assertions --- internal/reflect/primitive.go | 36 ++++++++++--- internal/reflect/primitive_test.go | 43 +++++++++++++++- .../testtypes/boolwithvalidateattribute.go | 50 +++++++++++++++++++ 3 files changed, 121 insertions(+), 8 deletions(-) diff --git a/internal/reflect/primitive.go b/internal/reflect/primitive.go index 601259d69..813e7e47f 100644 --- a/internal/reflect/primitive.go +++ b/internal/reflect/primitive.go @@ -86,6 +86,10 @@ func FromString(ctx context.Context, typ attr.Type, val string, path path.Path) ) diags.Append(resp.Diagnostics...) + + if diags.HasError() { + return nil, diags + } default: //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { @@ -111,18 +115,36 @@ func FromBool(ctx context.Context, typ attr.Type, val bool, path path.Path) (att } tfBool := tftypes.NewValue(tftypes.Bool, val) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfBool, path)...) + b, err := typ.ValueFromTerraform(ctx, tfBool) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := b.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfBool, path)...) - b, err := typ.ValueFromTerraform(ctx, tfBool) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } return b, diags diff --git a/internal/reflect/primitive_test.go b/internal/reflect/primitive_test.go index 56690ee04..729b42749 100644 --- a/internal/reflect/primitive_test.go +++ b/internal/reflect/primitive_test.go @@ -9,13 +9,14 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" refl "github.com/hashicorp/terraform-plugin-framework/internal/reflect" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestPrimitive_string(t *testing.T) { @@ -105,6 +106,19 @@ func TestFromString(t *testing.T) { testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + val: "mystring", + typ: testtypes.StringTypeWithValidateAttributeWarning{}, + expected: testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("mystring"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, "WithValidateError": { val: "mystring", typ: testtypes.StringTypeWithValidateError{}, @@ -112,6 +126,13 @@ func TestFromString(t *testing.T) { testtypes.TestErrorDiagnostic(path.Empty()), }, }, + "WithValidateAttributeError": { + val: "mystring", + typ: testtypes.StringTypeWithValidateAttributeError{}, + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, } for name, tc := range cases { @@ -162,6 +183,19 @@ func TestFromBool(t *testing.T) { testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + val: true, + typ: testtypes.BoolTypeWithValidateAttributeWarning{}, + expected: testtypes.BoolValueWithValidateAttributeWarning{ + Bool: testtypes.Bool{ + Bool: types.BoolValue(true), + CreatedBy: testtypes.BoolTypeWithValidateWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, "WithValidateError": { val: true, typ: testtypes.BoolTypeWithValidateError{}, @@ -169,6 +203,13 @@ func TestFromBool(t *testing.T) { testtypes.TestErrorDiagnostic(path.Empty()), }, }, + "WithValidateAttributeError": { + val: true, + typ: testtypes.BoolTypeWithValidateAttributeError{}, + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, } for name, tc := range cases { diff --git a/internal/testing/testtypes/boolwithvalidateattribute.go b/internal/testing/testtypes/boolwithvalidateattribute.go index 7e9b4b248..73aa1b37e 100644 --- a/internal/testing/testtypes/boolwithvalidateattribute.go +++ b/internal/testing/testtypes/boolwithvalidateattribute.go @@ -62,3 +62,53 @@ func (v BoolValueWithValidateAttributeError) Equal(o attr.Value) bool { func (v BoolValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) } + +type BoolTypeWithValidateAttributeWarning struct { + BoolType +} + +func (t BoolTypeWithValidateAttributeWarning) Equal(o attr.Type) bool { + other, ok := o.(BoolTypeWithValidateAttributeWarning) + if !ok { + return false + } + return t == other +} + +func (t BoolTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.BoolType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newBool, ok := val.(Bool) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", val) + } + + newBool.CreatedBy = t + + return BoolValueWithValidateAttributeWarning{ + newBool, + }, nil +} + +var _ xattr.ValidateableAttribute = BoolValueWithValidateAttributeWarning{} + +type BoolValueWithValidateAttributeWarning struct { + Bool +} + +func (v BoolValueWithValidateAttributeWarning) Equal(o attr.Value) bool { + ob, ok := o.(BoolValueWithValidateAttributeWarning) + + if !ok { + return false + } + + return v.Bool.Equal(ob.Bool) +} + +func (v BoolValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) +} From f410606c89158bbb1c05d2d2d30e8967728b2271 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 22 Mar 2024 14:54:21 +0000 Subject: [PATCH 13/62] Renaming interfaces --- types/validation/bool_attribute.go | 18 ------------------ types/validation/bool_parameter.go | 17 ----------------- types/validation/bool_value.go | 27 +++++++++++++++++++++++++++ types/validation/float64_attribute.go | 18 ------------------ types/validation/float64_parameter.go | 17 ----------------- types/validation/float64_value.go | 27 +++++++++++++++++++++++++++ types/validation/int64_attribute.go | 18 ------------------ types/validation/int64_parameter.go | 17 ----------------- types/validation/int64_value.go | 27 +++++++++++++++++++++++++++ types/validation/list_attribute.go | 18 ------------------ types/validation/list_parameter.go | 17 ----------------- types/validation/list_value.go | 27 +++++++++++++++++++++++++++ types/validation/map_attribute.go | 18 ------------------ types/validation/map_parameter.go | 17 ----------------- types/validation/map_value.go | 27 +++++++++++++++++++++++++++ types/validation/number_attribute.go | 18 ------------------ types/validation/number_parameter.go | 17 ----------------- types/validation/number_value.go | 27 +++++++++++++++++++++++++++ types/validation/object_attribute.go | 18 ------------------ types/validation/object_parameter.go | 17 ----------------- types/validation/object_value.go | 27 +++++++++++++++++++++++++++ types/validation/set_attribute.go | 18 ------------------ types/validation/set_parameter.go | 17 ----------------- types/validation/set_value.go | 27 +++++++++++++++++++++++++++ types/validation/string_attribute.go | 18 ------------------ types/validation/string_parameter.go | 17 ----------------- types/validation/string_value.go | 27 +++++++++++++++++++++++++++ 27 files changed, 243 insertions(+), 315 deletions(-) delete mode 100644 types/validation/bool_attribute.go delete mode 100644 types/validation/bool_parameter.go create mode 100644 types/validation/bool_value.go delete mode 100644 types/validation/float64_attribute.go delete mode 100644 types/validation/float64_parameter.go create mode 100644 types/validation/float64_value.go delete mode 100644 types/validation/int64_attribute.go delete mode 100644 types/validation/int64_parameter.go create mode 100644 types/validation/int64_value.go delete mode 100644 types/validation/list_attribute.go delete mode 100644 types/validation/list_parameter.go create mode 100644 types/validation/list_value.go delete mode 100644 types/validation/map_attribute.go delete mode 100644 types/validation/map_parameter.go create mode 100644 types/validation/map_value.go delete mode 100644 types/validation/number_attribute.go delete mode 100644 types/validation/number_parameter.go create mode 100644 types/validation/number_value.go delete mode 100644 types/validation/object_attribute.go delete mode 100644 types/validation/object_parameter.go create mode 100644 types/validation/object_value.go delete mode 100644 types/validation/set_attribute.go delete mode 100644 types/validation/set_parameter.go create mode 100644 types/validation/set_value.go delete mode 100644 types/validation/string_attribute.go delete mode 100644 types/validation/string_parameter.go create mode 100644 types/validation/string_value.go diff --git a/types/validation/bool_attribute.go b/types/validation/bool_attribute.go deleted file mode 100644 index 8b3eed64e..000000000 --- a/types/validation/bool_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// BoolAttributeWithValidate extends the basetypes.BoolValuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type BoolAttributeWithValidate interface { - basetypes.BoolValuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/bool_parameter.go b/types/validation/bool_parameter.go deleted file mode 100644 index c37c7ef57..000000000 --- a/types/validation/bool_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// BoolParameterWithValidate extends the basetypes.BoolValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type BoolParameterWithValidate interface { - basetypes.BoolValuable - - ValidateableParameter -} diff --git a/types/validation/bool_value.go b/types/validation/bool_value.go new file mode 100644 index 000000000..bebae323b --- /dev/null +++ b/types/validation/bool_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// BoolValuableWithValidateableAttribute extends the basetypes.BoolValuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type BoolValuableWithValidateableAttribute interface { + basetypes.BoolValuable + + xattr.ValidateableAttribute +} + +// BoolValuableWithValidateableParameter extends the basetypes.BoolValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type BoolValuableWithValidateableParameter interface { + basetypes.BoolValuable + + ValidateableParameter +} diff --git a/types/validation/float64_attribute.go b/types/validation/float64_attribute.go deleted file mode 100644 index c287a63e8..000000000 --- a/types/validation/float64_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// Float64AttributeWithValidate extends the basetypes.Float64Valuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type Float64AttributeWithValidate interface { - basetypes.Float64Valuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/float64_parameter.go b/types/validation/float64_parameter.go deleted file mode 100644 index 05b39034c..000000000 --- a/types/validation/float64_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// Float64ParameterWithValidate extends the basetypes.Float64Valuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type Float64ParameterWithValidate interface { - basetypes.Float64Valuable - - ValidateableParameter -} diff --git a/types/validation/float64_value.go b/types/validation/float64_value.go new file mode 100644 index 000000000..8dc119f33 --- /dev/null +++ b/types/validation/float64_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// Float64ValuableWithValidateableAttribute extends the basetypes.Float64Valuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type Float64ValuableWithValidateableAttribute interface { + basetypes.Float64Valuable + + xattr.ValidateableAttribute +} + +// Float64ValuableWithValidateableParameter extends the basetypes.Float64Valuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type Float64ValuableWithValidateableParameter interface { + basetypes.Float64Valuable + + ValidateableParameter +} diff --git a/types/validation/int64_attribute.go b/types/validation/int64_attribute.go deleted file mode 100644 index a9e7b38af..000000000 --- a/types/validation/int64_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// Int64AttributeWithValidate extends the basetypes.Int64Valuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type Int64AttributeWithValidate interface { - basetypes.Int64Valuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/int64_parameter.go b/types/validation/int64_parameter.go deleted file mode 100644 index 8161cef26..000000000 --- a/types/validation/int64_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// Int64ParameterWithValidate extends the basetypes.Int64Valuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type Int64ParameterWithValidate interface { - basetypes.Int64Valuable - - ValidateableParameter -} diff --git a/types/validation/int64_value.go b/types/validation/int64_value.go new file mode 100644 index 000000000..5e0fa55ea --- /dev/null +++ b/types/validation/int64_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// Int64ValuableWithValidateableAttribute extends the basetypes.Int64Valuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type Int64ValuableWithValidateableAttribute interface { + basetypes.Int64Valuable + + xattr.ValidateableAttribute +} + +// Int64ValuableWithValidateableParameter extends the basetypes.Int64Valuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type Int64ValuableWithValidateableParameter interface { + basetypes.Int64Valuable + + ValidateableParameter +} diff --git a/types/validation/list_attribute.go b/types/validation/list_attribute.go deleted file mode 100644 index ee05d7730..000000000 --- a/types/validation/list_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// ListAttributeWithValidate extends the basetypes.ListValuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type ListAttributeWithValidate interface { - basetypes.ListValuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/list_parameter.go b/types/validation/list_parameter.go deleted file mode 100644 index 8507e5813..000000000 --- a/types/validation/list_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// ListParameterWithValidate extends the basetypes.ListValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type ListParameterWithValidate interface { - basetypes.ListValuable - - ValidateableParameter -} diff --git a/types/validation/list_value.go b/types/validation/list_value.go new file mode 100644 index 000000000..c2ce54d3b --- /dev/null +++ b/types/validation/list_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// ListValuableWithValidateableAttribute extends the basetypes.ListValuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type ListValuableWithValidateableAttribute interface { + basetypes.ListValuable + + xattr.ValidateableAttribute +} + +// ListValuableWithValidateableParameter extends the basetypes.ListValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type ListValuableWithValidateableParameter interface { + basetypes.ListValuable + + ValidateableParameter +} diff --git a/types/validation/map_attribute.go b/types/validation/map_attribute.go deleted file mode 100644 index f295a8919..000000000 --- a/types/validation/map_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// MapAttributeWithValidate extends the basetypes.MapValuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type MapAttributeWithValidate interface { - basetypes.MapValuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/map_parameter.go b/types/validation/map_parameter.go deleted file mode 100644 index 3c369f1c0..000000000 --- a/types/validation/map_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// MapParameterWithValidate extends the basetypes.MapValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type MapParameterWithValidate interface { - basetypes.MapValuable - - ValidateableParameter -} diff --git a/types/validation/map_value.go b/types/validation/map_value.go new file mode 100644 index 000000000..501708494 --- /dev/null +++ b/types/validation/map_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// MapValuableWithValidateableAttribute extends the basetypes.MapValuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type MapValuableWithValidateableAttribute interface { + basetypes.MapValuable + + xattr.ValidateableAttribute +} + +// MapValuableWithValidateableParameter extends the basetypes.MapValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type MapValuableWithValidateableParameter interface { + basetypes.MapValuable + + ValidateableParameter +} diff --git a/types/validation/number_attribute.go b/types/validation/number_attribute.go deleted file mode 100644 index fa9259742..000000000 --- a/types/validation/number_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// NumberAttributeWithValidate extends the basetypes.NumberValuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type NumberAttributeWithValidate interface { - basetypes.NumberValuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/number_parameter.go b/types/validation/number_parameter.go deleted file mode 100644 index ba9cee87f..000000000 --- a/types/validation/number_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// NumberParameterWithValidate extends the basetypes.NumberValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type NumberParameterWithValidate interface { - basetypes.NumberValuable - - ValidateableParameter -} diff --git a/types/validation/number_value.go b/types/validation/number_value.go new file mode 100644 index 000000000..9f6fb0f9c --- /dev/null +++ b/types/validation/number_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// NumberValuableWithValidateableAttribute extends the basetypes.NumberValuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type NumberValuableWithValidateableAttribute interface { + basetypes.NumberValuable + + xattr.ValidateableAttribute +} + +// NumberValuableWithValidateableParameter extends the basetypes.NumberValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type NumberValuableWithValidateableParameter interface { + basetypes.NumberValuable + + ValidateableParameter +} diff --git a/types/validation/object_attribute.go b/types/validation/object_attribute.go deleted file mode 100644 index 478b4680d..000000000 --- a/types/validation/object_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// ObjectAttributeWithValidate extends the basetypes.ObjectValuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type ObjectAttributeWithValidate interface { - basetypes.ObjectValuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/object_parameter.go b/types/validation/object_parameter.go deleted file mode 100644 index 194172cb2..000000000 --- a/types/validation/object_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// ObjectParameterWithValidate extends the basetypes.ObjectValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type ObjectParameterWithValidate interface { - basetypes.ObjectValuable - - ValidateableParameter -} diff --git a/types/validation/object_value.go b/types/validation/object_value.go new file mode 100644 index 000000000..2e361934e --- /dev/null +++ b/types/validation/object_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// ObjectValuableWithValidateableAttribute extends the basetypes.ObjectValuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type ObjectValuableWithValidateableAttribute interface { + basetypes.ObjectValuable + + xattr.ValidateableAttribute +} + +// ObjectValuableWithValidateableParameter extends the basetypes.ObjectValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type ObjectValuableWithValidateableParameter interface { + basetypes.ObjectValuable + + ValidateableParameter +} diff --git a/types/validation/set_attribute.go b/types/validation/set_attribute.go deleted file mode 100644 index c36c18e42..000000000 --- a/types/validation/set_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// SetAttributeWithValidate extends the basetypes.SetValuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type SetAttributeWithValidate interface { - basetypes.SetValuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/set_parameter.go b/types/validation/set_parameter.go deleted file mode 100644 index 448bca0d9..000000000 --- a/types/validation/set_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// SetParameterWithValidate extends the basetypes.SetValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type SetParameterWithValidate interface { - basetypes.SetValuable - - ValidateableParameter -} diff --git a/types/validation/set_value.go b/types/validation/set_value.go new file mode 100644 index 000000000..2564a35f7 --- /dev/null +++ b/types/validation/set_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// SetValuableWithValidateableAttribute extends the basetypes.SetValuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type SetValuableWithValidateableAttribute interface { + basetypes.SetValuable + + xattr.ValidateableAttribute +} + +// SetValuableWithValidateableParameter extends the basetypes.SetValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type SetValuableWithValidateableParameter interface { + basetypes.SetValuable + + ValidateableParameter +} diff --git a/types/validation/string_attribute.go b/types/validation/string_attribute.go deleted file mode 100644 index b02e2ada9..000000000 --- a/types/validation/string_attribute.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// StringAttributeWithValidate extends the basetypes.StringValuable interface to include a -// ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type StringAttributeWithValidate interface { - basetypes.StringValuable - - xattr.ValidateableAttribute -} diff --git a/types/validation/string_parameter.go b/types/validation/string_parameter.go deleted file mode 100644 index 307becdb7..000000000 --- a/types/validation/string_parameter.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// StringParameterWithValidate extends the basetypes.StringValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type StringParameterWithValidate interface { - basetypes.StringValuable - - ValidateableParameter -} diff --git a/types/validation/string_value.go b/types/validation/string_value.go new file mode 100644 index 000000000..8f888b7df --- /dev/null +++ b/types/validation/string_value.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validation + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// StringValuableWithValidateableAttribute extends the basetypes.StringValuable interface to include a +// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with +// the Value. +type StringValuableWithValidateableAttribute interface { + basetypes.StringValuable + + xattr.ValidateableAttribute +} + +// StringValuableWithValidateableParameter extends the basetypes.StringValuable interface to include a +// ValidateableParameter interface, used to bundle consistent parameter validation logic with +// the Value. +type StringValuableWithValidateableParameter interface { + basetypes.StringValuable + + ValidateableParameter +} From 90dd5435590fde83c268426b9d8778da940077d9 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Fri, 29 Mar 2024 10:52:57 -0400 Subject: [PATCH 14/62] Add `function/validator` package --- function/parameter_validation.go | 95 ++++++++++++++++++++++++++++++++ function/validator/bool.go | 31 +++++++++++ function/validator/dynamic.go | 31 +++++++++++ function/validator/float64.go | 31 +++++++++++ function/validator/int64.go | 31 +++++++++++ function/validator/list.go | 31 +++++++++++ function/validator/map.go | 31 +++++++++++ function/validator/number.go | 31 +++++++++++ function/validator/object.go | 31 +++++++++++ function/validator/set.go | 31 +++++++++++ function/validator/string.go | 31 +++++++++++ 11 files changed, 405 insertions(+) create mode 100644 function/parameter_validation.go create mode 100644 function/validator/bool.go create mode 100644 function/validator/dynamic.go create mode 100644 function/validator/float64.go create mode 100644 function/validator/int64.go create mode 100644 function/validator/list.go create mode 100644 function/validator/map.go create mode 100644 function/validator/number.go create mode 100644 function/validator/object.go create mode 100644 function/validator/set.go create mode 100644 function/validator/string.go diff --git a/function/parameter_validation.go b/function/parameter_validation.go new file mode 100644 index 000000000..21ad8f686 --- /dev/null +++ b/function/parameter_validation.go @@ -0,0 +1,95 @@ +package function + +import ( + "github.com/hashicorp/terraform-plugin-framework/function/validator" +) + +// ParameterWithBoolValidators is an optional interface on Parameter which +// enables Bool validation support. +type ParameterWithBoolValidators interface { + Parameter + + // BoolValidators should return a list of Bool validators. + BoolValidators() []validator.Bool +} + +// ParameterWithInt64Validators is an optional interface on Parameter which +// enables Int64 validation support. +type ParameterWithInt64Validators interface { + Parameter + + // Int64Validators should return a list of Int64 validators. + Int64Validators() []validator.Int64 +} + +// ParameterWithFloat64Validators is an optional interface on Parameter which +// enables Float64 validation support. +type ParameterWithFloat64Validators interface { + Parameter + + // Float64Validators should return a list of Float64 validators. + Float64Validators() []validator.Float64 +} + +// ParameterWithDynamicValidators is an optional interface on Parameter which +// enables Dynamic validation support. +type ParameterWithDynamicValidators interface { + Parameter + + // DynamicValidators should return a list of Dynamic validators. + DynamicValidators() []validator.Dynamic +} + +// ParameterWithListValidators is an optional interface on Parameter which +// enables List validation support. +type ParameterWithListValidators interface { + Parameter + + // ListValidators should return a list of List validators. + ListValidators() []validator.List +} + +// ParameterWithMapValidators is an optional interface on Parameter which +// enables Map validation support. +type ParameterWithMapValidators interface { + Parameter + + // MapValidators should return a list of Map validators. + MapValidators() []validator.Map +} + +// ParameterWithNumberValidators is an optional interface on Parameter which +// enables Number validation support. +type ParameterWithNumberValidators interface { + Parameter + + // NumberValidators should return a list of Map validators. + NumberValidators() []validator.Number +} + +// ParameterWithObjectValidators is an optional interface on Parameter which +// enables Object validation support. +type ParameterWithObjectValidators interface { + Parameter + + // ObjectValidators should return a list of Object validators. + ObjectValidators() []validator.Object +} + +// ParameterWithSetValidators is an optional interface on Parameter which +// enables Set validation support. +type ParameterWithSetValidators interface { + Parameter + + // SetValidators should return a list of Set validators. + SetValidators() []validator.Set +} + +// ParameterWithStringValidators is an optional interface on Parameter which +// enables String validation support. +type ParameterWithStringValidators interface { + Parameter + + // StringValidators should return a list of String validators. + StringValidators() []validator.String +} diff --git a/function/validator/bool.go b/function/validator/bool.go new file mode 100644 index 000000000..6388defdd --- /dev/null +++ b/function/validator/bool.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Bool is a function validator for types.Bool parameters. +type Bool interface { + + // ValidateBool should perform the validation. + ValidateBool(context.Context, BoolRequest, *BoolResponse) +} + +// BoolRequest is a request for types.Bool schema validation. +type BoolRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Bool +} + +// BoolResponse is a response to a BoolRequest. +type BoolResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/dynamic.go b/function/validator/dynamic.go new file mode 100644 index 000000000..cc7d46ed5 --- /dev/null +++ b/function/validator/dynamic.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Dynamic is a function validator for types.Dynamic parameters. +type Dynamic interface { + + // ValidateDynamic should perform the validation. + ValidateDynamic(context.Context, DynamicRequest, *DynamicResponse) +} + +// DynamicRequest is a request for types.Dynamic schema validation. +type DynamicRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Dynamic +} + +// DynamicResponse is a response to a DynamicRequest. +type DynamicResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/float64.go b/function/validator/float64.go new file mode 100644 index 000000000..9bb6c91b3 --- /dev/null +++ b/function/validator/float64.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Float64 is a function validator for types.Float64 parameters. +type Float64 interface { + + // ValidateFloat64 should perform the validation. + ValidateFloat64(context.Context, Float64Request, *Float64Response) +} + +// Float64Request is a request for types.Float64 schema validation. +type Float64Request struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Float64 +} + +// Float64Response is a response to a Float64Request. +type Float64Response struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/int64.go b/function/validator/int64.go new file mode 100644 index 000000000..08d042275 --- /dev/null +++ b/function/validator/int64.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Int64 is a function validator for types.Int64 parameters. +type Int64 interface { + + // ValidateInt64 should perform the validation. + ValidateInt64(context.Context, Int64Request, *Int64Response) +} + +// Int64Request is a request for types.Int64 schema validation. +type Int64Request struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Int64 +} + +// Int64Response is a response to a Int64Request. +type Int64Response struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/list.go b/function/validator/list.go new file mode 100644 index 000000000..b4088e2c0 --- /dev/null +++ b/function/validator/list.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// List is a function validator for types.List parameters. +type List interface { + + // ValidateList should perform the validation. + ValidateList(context.Context, ListRequest, *ListResponse) +} + +// ListRequest is a request for types.List schema validation. +type ListRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.List +} + +// ListResponse is a response to a ListRequest. +type ListResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/map.go b/function/validator/map.go new file mode 100644 index 000000000..118fba59d --- /dev/null +++ b/function/validator/map.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Map is a function validator for types.Map parameters. +type Map interface { + + // ValidateMap should perform the validation. + ValidateMap(context.Context, MapRequest, *MapResponse) +} + +// MapRequest is a request for types.Map schema validation. +type MapRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Map +} + +// MapResponse is a response to a MapRequest. +type MapResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/number.go b/function/validator/number.go new file mode 100644 index 000000000..2e42b7ee9 --- /dev/null +++ b/function/validator/number.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Number is a function validator for types.Number parameters. +type Number interface { + + // ValidateNumber should perform the validation. + ValidateNumber(context.Context, NumberRequest, *NumberResponse) +} + +// NumberRequest is a request for types.Number schema validation. +type NumberRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Number +} + +// NumberResponse is a response to a NumberRequest. +type NumberResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/object.go b/function/validator/object.go new file mode 100644 index 000000000..ba07e931b --- /dev/null +++ b/function/validator/object.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Object is a function validator for types.Object parameters. +type Object interface { + + // ValidateObject should perform the validation. + ValidateObject(context.Context, ObjectRequest, *ObjectResponse) +} + +// ObjectRequest is a request for types.Object schema validation. +type ObjectRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Object +} + +// ObjectResponse is a response to a ObjectRequest. +type ObjectResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/set.go b/function/validator/set.go new file mode 100644 index 000000000..c29b8179e --- /dev/null +++ b/function/validator/set.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Set is a function validator for types.Set parameters. +type Set interface { + + // ValidateSet should perform the validation. + ValidateSet(context.Context, SetRequest, *SetResponse) +} + +// SetRequest is a request for types.Set schema validation. +type SetRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.Set +} + +// SetResponse is a response to a SetRequest. +type SetResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} diff --git a/function/validator/string.go b/function/validator/string.go new file mode 100644 index 000000000..4322f0cdc --- /dev/null +++ b/function/validator/string.go @@ -0,0 +1,31 @@ +package validator + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// String is a function validator for types.String parameters. +type String interface { + + // ValidateString should perform the validation. + ValidateString(context.Context, StringRequest, *StringResponse) +} + +// StringRequest is a request for types.String schema validation. +type StringRequest struct { + // ArgumentPosition contains the position of the argument for validation. + // Use this position for any response diagnostics. + ArgumentPosition int + + // Value contains the value of the argument for validation. + Value types.String +} + +// StringResponse is a response to a StringRequest. +type StringResponse struct { + // Error is a function error generated during validation of the Value. + Error *function.FuncError +} From fc554abe1f64b25fb8d1e67de4c2e2d205e98246 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Fri, 29 Mar 2024 10:54:51 -0400 Subject: [PATCH 15/62] Implement parameter validators in parameter types --- function/bool_parameter.go | 10 ++++++++++ function/dynamic_parameter.go | 10 ++++++++++ function/float64_parameter.go | 10 ++++++++++ function/int64_parameter.go | 10 ++++++++++ function/list_parameter.go | 10 ++++++++++ function/map_parameter.go | 10 ++++++++++ function/number_parameter.go | 10 ++++++++++ function/object_parameter.go | 10 ++++++++++ function/set_parameter.go | 10 ++++++++++ function/string_parameter.go | 11 +++++++++++ 10 files changed, 101 insertions(+) diff --git a/function/bool_parameter.go b/function/bool_parameter.go index 4c6ec94a9..dc90dbdcb 100644 --- a/function/bool_parameter.go +++ b/function/bool_parameter.go @@ -5,11 +5,13 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) // Ensure the implementation satisifies the desired interfaces. var _ Parameter = BoolParameter{} +var _ ParameterWithBoolValidators = BoolParameter{} // BoolParameter represents a function parameter that is a boolean. // @@ -70,6 +72,14 @@ type BoolParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of bool validators that should be applied to the + // parameter. + Validators []validator.Bool +} + +func (p BoolParameter) BoolValidators() []validator.Bool { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/dynamic_parameter.go b/function/dynamic_parameter.go index 1af3c71d0..0df50ac6e 100644 --- a/function/dynamic_parameter.go +++ b/function/dynamic_parameter.go @@ -5,11 +5,13 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) // Ensure the implementation satisifies the desired interfaces. var _ Parameter = DynamicParameter{} +var _ ParameterWithDynamicValidators = DynamicParameter{} // DynamicParameter represents a function parameter that is a dynamic, rather // than a static type. Static types are always preferable over dynamic @@ -65,6 +67,14 @@ type DynamicParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of dynamic validators that should be applied to the + // parameter. + Validators []validator.Dynamic +} + +func (p DynamicParameter) DynamicValidators() []validator.Dynamic { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/float64_parameter.go b/function/float64_parameter.go index 221fb4f22..734f3ac32 100644 --- a/function/float64_parameter.go +++ b/function/float64_parameter.go @@ -5,11 +5,13 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) // Ensure the implementation satisifies the desired interfaces. var _ Parameter = Float64Parameter{} +var _ ParameterWithFloat64Validators = Float64Parameter{} // Float64Parameter represents a function parameter that is a 64-bit floating // point number. @@ -67,6 +69,14 @@ type Float64Parameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of float64 validators that should be applied to the + // parameter. + Validators []validator.Float64 +} + +func (p Float64Parameter) Float64Validators() []validator.Float64 { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/int64_parameter.go b/function/int64_parameter.go index 3fd6d8852..8e0b41b22 100644 --- a/function/int64_parameter.go +++ b/function/int64_parameter.go @@ -5,11 +5,13 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) // Ensure the implementation satisifies the desired interfaces. var _ Parameter = Int64Parameter{} +var _ ParameterWithInt64Validators = Int64Parameter{} // Int64Parameter represents a function parameter that is a 64-bit integer. // @@ -66,6 +68,14 @@ type Int64Parameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of int64 validators that should be applied to the + // parameter. + Validators []validator.Int64 +} + +func (p Int64Parameter) Int64Validators() []validator.Int64 { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/list_parameter.go b/function/list_parameter.go index 69d54da94..d1fc59597 100644 --- a/function/list_parameter.go +++ b/function/list_parameter.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -17,6 +18,7 @@ import ( var ( _ Parameter = ListParameter{} _ fwfunction.ParameterWithValidateImplementation = ListParameter{} + _ ParameterWithListValidators = ListParameter{} ) // ListParameter represents a function parameter that is an ordered list of a @@ -82,6 +84,14 @@ type ListParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of list validators that should be applied to the + // parameter. + Validators []validator.List +} + +func (p ListParameter) ListValidators() []validator.List { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/map_parameter.go b/function/map_parameter.go index 457720ea2..8489f2613 100644 --- a/function/map_parameter.go +++ b/function/map_parameter.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -17,6 +18,7 @@ import ( var ( _ Parameter = MapParameter{} _ fwfunction.ParameterWithValidateImplementation = MapParameter{} + _ ParameterWithMapValidators = MapParameter{} ) // MapParameter represents a function parameter that is a mapping of a single @@ -82,6 +84,14 @@ type MapParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of map validators that should be applied to the + // parameter. + Validators []validator.Map +} + +func (p MapParameter) MapValidators() []validator.Map { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/number_parameter.go b/function/number_parameter.go index a4899fe79..d8e0886b7 100644 --- a/function/number_parameter.go +++ b/function/number_parameter.go @@ -5,11 +5,13 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) // Ensure the implementation satisifies the desired interfaces. var _ Parameter = NumberParameter{} +var _ ParameterWithNumberValidators = NumberParameter{} // NumberParameter represents a function parameter that is a 512-bit arbitrary // precision number. @@ -65,6 +67,14 @@ type NumberParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of validators that can be used to validate the + // parameter. + Validators []validator.Number +} + +func (p NumberParameter) NumberValidators() []validator.Number { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/object_parameter.go b/function/object_parameter.go index e558a7549..cf21a99b1 100644 --- a/function/object_parameter.go +++ b/function/object_parameter.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -17,6 +18,7 @@ import ( var ( _ Parameter = ObjectParameter{} _ fwfunction.ParameterWithValidateImplementation = ObjectParameter{} + _ ParameterWithObjectValidators = ObjectParameter{} ) // ObjectParameter represents a function parameter that is a mapping of @@ -84,6 +86,14 @@ type ObjectParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of object validators that should be applied to the + // parameter. + Validators []validator.Object +} + +func (p ObjectParameter) ObjectValidators() []validator.Object { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/set_parameter.go b/function/set_parameter.go index 0774c559f..8888a6205 100644 --- a/function/set_parameter.go +++ b/function/set_parameter.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -17,6 +18,7 @@ import ( var ( _ Parameter = SetParameter{} _ fwfunction.ParameterWithValidateImplementation = SetParameter{} + _ ParameterWithSetValidators = SetParameter{} ) // SetParameter represents a function parameter that is an unordered set of a @@ -82,6 +84,14 @@ type SetParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of set validators that should be applied to the + // parameter. + Validators []validator.Set +} + +func (p SetParameter) SetValidators() []validator.Set { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. diff --git a/function/string_parameter.go b/function/string_parameter.go index 8584f94d4..9064a540f 100644 --- a/function/string_parameter.go +++ b/function/string_parameter.go @@ -5,11 +5,13 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) // Ensure the implementation satisifies the desired interfaces. var _ Parameter = StringParameter{} +var _ ParameterWithStringValidators = StringParameter{} // StringParameter represents a function parameter that is a string. // @@ -66,6 +68,15 @@ type StringParameter struct { // alphabetical character and followed by alphanumeric or underscore // characters. Name string + + // Validators is a list of string validators that should be applied to the + // parameter. + Validators []validator.String +} + +// StringValidators returns the string validators for the parameter. +func (p StringParameter) StringValidators() []validator.String { + return p.Validators } // GetAllowNullValue returns if the parameter accepts a null value. From 75fb7083847ee67a6fa3424b8445ec0a4b7e8266 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Fri, 29 Mar 2024 10:55:49 -0400 Subject: [PATCH 16/62] Initial implementation of parameter validation logic --- internal/fromproto5/arguments_data.go | 155 ++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 4edca1a86..6c72b537b 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -12,8 +12,10 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/validation" ) @@ -162,6 +164,159 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } + switch parameterWithValidators := parameter.(type) { + case function.ParameterWithBoolValidators: + for _, functionValidator := range parameterWithValidators.BoolValidators() { + req := validator.BoolRequest{ + ArgumentPosition: position, + Value: attrValue.(types.Bool), + } + resp := &validator.BoolResponse{} + functionValidator.ValidateBool(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithDynamicValidators: + for _, functionValidator := range parameterWithValidators.DynamicValidators() { + req := validator.DynamicRequest{ + ArgumentPosition: position, + Value: attrValue.(types.Dynamic), + } + resp := &validator.DynamicResponse{} + functionValidator.ValidateDynamic(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithFloat64Validators: + for _, functionValidator := range parameterWithValidators.Float64Validators() { + req := validator.Float64Request{ + ArgumentPosition: position, + Value: attrValue.(types.Float64), + } + resp := &validator.Float64Response{} + functionValidator.ValidateFloat64(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithInt64Validators: + for _, functionValidator := range parameterWithValidators.Int64Validators() { + req := validator.Int64Request{ + ArgumentPosition: position, + Value: attrValue.(types.Int64), + } + resp := &validator.Int64Response{} + functionValidator.ValidateInt64(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithListValidators: + for _, functionValidator := range parameterWithValidators.ListValidators() { + req := validator.ListRequest{ + ArgumentPosition: position, + Value: attrValue.(types.List), + } + resp := &validator.ListResponse{} + functionValidator.ValidateList(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithMapValidators: + for _, functionValidator := range parameterWithValidators.MapValidators() { + req := validator.MapRequest{ + ArgumentPosition: position, + Value: attrValue.(types.Map), + } + resp := &validator.MapResponse{} + functionValidator.ValidateMap(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithNumberValidators: + for _, functionValidator := range parameterWithValidators.NumberValidators() { + req := validator.NumberRequest{ + ArgumentPosition: position, + Value: attrValue.(types.Number), + } + resp := &validator.NumberResponse{} + functionValidator.ValidateNumber(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithObjectValidators: + for _, functionValidator := range parameterWithValidators.ObjectValidators() { + req := validator.ObjectRequest{ + ArgumentPosition: position, + Value: attrValue.(types.Object), + } + resp := &validator.ObjectResponse{} + functionValidator.ValidateObject(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithSetValidators: + for _, functionValidator := range parameterWithValidators.SetValidators() { + req := validator.SetRequest{ + ArgumentPosition: position, + Value: attrValue.(types.Set), + } + resp := &validator.SetResponse{} + functionValidator.ValidateSet(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithStringValidators: + for _, functionValidator := range parameterWithValidators.StringValidators() { + req := validator.StringRequest{ + ArgumentPosition: position, + Value: attrValue.(types.String), + } + resp := &validator.StringResponse{} + functionValidator.ValidateString(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + } + if definition.VariadicParameter != nil && position >= len(definition.Parameters) { variadicValues = append(variadicValues, attrValue) From 240679afcadbfcb26b98f771fa880e5d7d1a90c2 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Fri, 29 Mar 2024 13:46:54 -0400 Subject: [PATCH 17/62] Refactor function parameter validators from `function/validator` package to `function` package. --- function/bool_parameter.go | 5 +- .../bool.go => bool_parameter_validator.go} | 13 ++-- function/dynamic_parameter.go | 5 +- ...amic.go => dynamic_parameter_validator.go} | 13 ++-- function/float64_parameter.go | 5 +- ...at64.go => float64_parameter_validator.go} | 13 ++-- function/int64_parameter.go | 5 +- .../int64.go => int64_parameter_validator.go} | 13 ++-- function/list_parameter.go | 5 +- .../list.go => list_parameter_validator.go} | 13 ++-- function/map_parameter.go | 5 +- .../map.go => map_parameter_validator.go} | 13 ++-- function/number_parameter.go | 5 +- ...umber.go => number_parameter_validator.go} | 13 ++-- function/object_parameter.go | 5 +- ...bject.go => object_parameter_validator.go} | 13 ++-- function/parameter_validation.go | 24 +++----- function/set_parameter.go | 5 +- .../set.go => set_parameter_validator.go} | 13 ++-- function/string_parameter.go | 5 +- ...tring.go => string_parameter_validator.go} | 11 ++-- internal/fromproto5/arguments_data.go | 61 +++++++++---------- internal/testing/testvalidator/bool.go | 18 +++++- 23 files changed, 135 insertions(+), 146 deletions(-) rename function/{validator/bool.go => bool_parameter_validator.go} (65%) rename function/{validator/dynamic.go => dynamic_parameter_validator.go} (64%) rename function/{validator/float64.go => float64_parameter_validator.go} (64%) rename function/{validator/int64.go => int64_parameter_validator.go} (65%) rename function/{validator/list.go => list_parameter_validator.go} (65%) rename function/{validator/map.go => map_parameter_validator.go} (65%) rename function/{validator/number.go => number_parameter_validator.go} (64%) rename function/{validator/object.go => object_parameter_validator.go} (64%) rename function/{validator/set.go => set_parameter_validator.go} (65%) rename function/{validator/string.go => string_parameter_validator.go} (70%) diff --git a/function/bool_parameter.go b/function/bool_parameter.go index dc90dbdcb..170e54dd9 100644 --- a/function/bool_parameter.go +++ b/function/bool_parameter.go @@ -5,7 +5,6 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -75,10 +74,10 @@ type BoolParameter struct { // Validators is a list of bool validators that should be applied to the // parameter. - Validators []validator.Bool + Validators []BoolValidator } -func (p BoolParameter) BoolValidators() []validator.Bool { +func (p BoolParameter) BoolValidators() []BoolValidator { return p.Validators } diff --git a/function/validator/bool.go b/function/bool_parameter_validator.go similarity index 65% rename from function/validator/bool.go rename to function/bool_parameter_validator.go index 6388defdd..dd91207ae 100644 --- a/function/validator/bool.go +++ b/function/bool_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Bool is a function validator for types.Bool parameters. -type Bool interface { +// BoolValidator is a function validator for types.Bool parameters. +type BoolValidator interface { - // ValidateBool should perform the validation. - ValidateBool(context.Context, BoolRequest, *BoolResponse) + // Validate should perform the validation. + Validate(context.Context, BoolRequest, *BoolResponse) } // BoolRequest is a request for types.Bool schema validation. @@ -27,5 +26,5 @@ type BoolRequest struct { // BoolResponse is a response to a BoolRequest. type BoolResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/dynamic_parameter.go b/function/dynamic_parameter.go index 0df50ac6e..a63b4e73c 100644 --- a/function/dynamic_parameter.go +++ b/function/dynamic_parameter.go @@ -5,7 +5,6 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -70,10 +69,10 @@ type DynamicParameter struct { // Validators is a list of dynamic validators that should be applied to the // parameter. - Validators []validator.Dynamic + Validators []DynamicValidator } -func (p DynamicParameter) DynamicValidators() []validator.Dynamic { +func (p DynamicParameter) DynamicValidators() []DynamicValidator { return p.Validators } diff --git a/function/validator/dynamic.go b/function/dynamic_parameter_validator.go similarity index 64% rename from function/validator/dynamic.go rename to function/dynamic_parameter_validator.go index cc7d46ed5..6b08adc14 100644 --- a/function/validator/dynamic.go +++ b/function/dynamic_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Dynamic is a function validator for types.Dynamic parameters. -type Dynamic interface { +// DynamicValidator is a function validator for types.Dynamic parameters. +type DynamicValidator interface { - // ValidateDynamic should perform the validation. - ValidateDynamic(context.Context, DynamicRequest, *DynamicResponse) + // Validate should perform the validation. + Validate(context.Context, DynamicRequest, *DynamicResponse) } // DynamicRequest is a request for types.Dynamic schema validation. @@ -27,5 +26,5 @@ type DynamicRequest struct { // DynamicResponse is a response to a DynamicRequest. type DynamicResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/float64_parameter.go b/function/float64_parameter.go index 734f3ac32..7d4de5ba7 100644 --- a/function/float64_parameter.go +++ b/function/float64_parameter.go @@ -5,7 +5,6 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -72,10 +71,10 @@ type Float64Parameter struct { // Validators is a list of float64 validators that should be applied to the // parameter. - Validators []validator.Float64 + Validators []Float64Validator } -func (p Float64Parameter) Float64Validators() []validator.Float64 { +func (p Float64Parameter) Float64Validators() []Float64Validator { return p.Validators } diff --git a/function/validator/float64.go b/function/float64_parameter_validator.go similarity index 64% rename from function/validator/float64.go rename to function/float64_parameter_validator.go index 9bb6c91b3..66d2a7985 100644 --- a/function/validator/float64.go +++ b/function/float64_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Float64 is a function validator for types.Float64 parameters. -type Float64 interface { +// Float64Validator is a function validator for types.Float64 parameters. +type Float64Validator interface { - // ValidateFloat64 should perform the validation. - ValidateFloat64(context.Context, Float64Request, *Float64Response) + // Validate should perform the validation. + Validate(context.Context, Float64Request, *Float64Response) } // Float64Request is a request for types.Float64 schema validation. @@ -27,5 +26,5 @@ type Float64Request struct { // Float64Response is a response to a Float64Request. type Float64Response struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/int64_parameter.go b/function/int64_parameter.go index 8e0b41b22..bf0e29ed7 100644 --- a/function/int64_parameter.go +++ b/function/int64_parameter.go @@ -5,7 +5,6 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -71,10 +70,10 @@ type Int64Parameter struct { // Validators is a list of int64 validators that should be applied to the // parameter. - Validators []validator.Int64 + Validators []Int64Validator } -func (p Int64Parameter) Int64Validators() []validator.Int64 { +func (p Int64Parameter) Int64Validators() []Int64Validator { return p.Validators } diff --git a/function/validator/int64.go b/function/int64_parameter_validator.go similarity index 65% rename from function/validator/int64.go rename to function/int64_parameter_validator.go index 08d042275..3c6526357 100644 --- a/function/validator/int64.go +++ b/function/int64_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Int64 is a function validator for types.Int64 parameters. -type Int64 interface { +// Int64Validator is a function validator for types.Int64 parameters. +type Int64Validator interface { - // ValidateInt64 should perform the validation. - ValidateInt64(context.Context, Int64Request, *Int64Response) + // Validate should perform the validation. + Validate(context.Context, Int64Request, *Int64Response) } // Int64Request is a request for types.Int64 schema validation. @@ -27,5 +26,5 @@ type Int64Request struct { // Int64Response is a response to a Int64Request. type Int64Response struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/list_parameter.go b/function/list_parameter.go index d1fc59597..9a8fe93b7 100644 --- a/function/list_parameter.go +++ b/function/list_parameter.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -87,10 +86,10 @@ type ListParameter struct { // Validators is a list of list validators that should be applied to the // parameter. - Validators []validator.List + Validators []ListValidator } -func (p ListParameter) ListValidators() []validator.List { +func (p ListParameter) ListValidators() []ListValidator { return p.Validators } diff --git a/function/validator/list.go b/function/list_parameter_validator.go similarity index 65% rename from function/validator/list.go rename to function/list_parameter_validator.go index b4088e2c0..d227c6cc4 100644 --- a/function/validator/list.go +++ b/function/list_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// List is a function validator for types.List parameters. -type List interface { +// ListValidator is a function validator for types.List parameters. +type ListValidator interface { - // ValidateList should perform the validation. - ValidateList(context.Context, ListRequest, *ListResponse) + // Validate should perform the validation. + Validate(context.Context, ListRequest, *ListResponse) } // ListRequest is a request for types.List schema validation. @@ -27,5 +26,5 @@ type ListRequest struct { // ListResponse is a response to a ListRequest. type ListResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/map_parameter.go b/function/map_parameter.go index 8489f2613..342b2e44c 100644 --- a/function/map_parameter.go +++ b/function/map_parameter.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -87,10 +86,10 @@ type MapParameter struct { // Validators is a list of map validators that should be applied to the // parameter. - Validators []validator.Map + Validators []MapValidator } -func (p MapParameter) MapValidators() []validator.Map { +func (p MapParameter) MapValidators() []MapValidator { return p.Validators } diff --git a/function/validator/map.go b/function/map_parameter_validator.go similarity index 65% rename from function/validator/map.go rename to function/map_parameter_validator.go index 118fba59d..240cdda4a 100644 --- a/function/validator/map.go +++ b/function/map_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Map is a function validator for types.Map parameters. -type Map interface { +// MapValidator is a function validator for types.Map parameters. +type MapValidator interface { - // ValidateMap should perform the validation. - ValidateMap(context.Context, MapRequest, *MapResponse) + // Validate should perform the validation. + Validate(context.Context, MapRequest, *MapResponse) } // MapRequest is a request for types.Map schema validation. @@ -27,5 +26,5 @@ type MapRequest struct { // MapResponse is a response to a MapRequest. type MapResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/number_parameter.go b/function/number_parameter.go index d8e0886b7..ba7a1d5d0 100644 --- a/function/number_parameter.go +++ b/function/number_parameter.go @@ -5,7 +5,6 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -70,10 +69,10 @@ type NumberParameter struct { // Validators is a list of validators that can be used to validate the // parameter. - Validators []validator.Number + Validators []NumberValidator } -func (p NumberParameter) NumberValidators() []validator.Number { +func (p NumberParameter) NumberValidators() []NumberValidator { return p.Validators } diff --git a/function/validator/number.go b/function/number_parameter_validator.go similarity index 64% rename from function/validator/number.go rename to function/number_parameter_validator.go index 2e42b7ee9..1dc486b75 100644 --- a/function/validator/number.go +++ b/function/number_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Number is a function validator for types.Number parameters. -type Number interface { +// NumberValidator is a function validator for types.Number parameters. +type NumberValidator interface { - // ValidateNumber should perform the validation. - ValidateNumber(context.Context, NumberRequest, *NumberResponse) + // Validate should perform the validation. + Validate(context.Context, NumberRequest, *NumberResponse) } // NumberRequest is a request for types.Number schema validation. @@ -27,5 +26,5 @@ type NumberRequest struct { // NumberResponse is a response to a NumberRequest. type NumberResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/object_parameter.go b/function/object_parameter.go index cf21a99b1..6d10d8df5 100644 --- a/function/object_parameter.go +++ b/function/object_parameter.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -89,10 +88,10 @@ type ObjectParameter struct { // Validators is a list of object validators that should be applied to the // parameter. - Validators []validator.Object + Validators []ObjectValidator } -func (p ObjectParameter) ObjectValidators() []validator.Object { +func (p ObjectParameter) ObjectValidators() []ObjectValidator { return p.Validators } diff --git a/function/validator/object.go b/function/object_parameter_validator.go similarity index 64% rename from function/validator/object.go rename to function/object_parameter_validator.go index ba07e931b..68b287fee 100644 --- a/function/validator/object.go +++ b/function/object_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Object is a function validator for types.Object parameters. -type Object interface { +// ObjectValidator is a function validator for types.Object parameters. +type ObjectValidator interface { - // ValidateObject should perform the validation. - ValidateObject(context.Context, ObjectRequest, *ObjectResponse) + // Validate should perform the validation. + Validate(context.Context, ObjectRequest, *ObjectResponse) } // ObjectRequest is a request for types.Object schema validation. @@ -27,5 +26,5 @@ type ObjectRequest struct { // ObjectResponse is a response to a ObjectRequest. type ObjectResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/parameter_validation.go b/function/parameter_validation.go index 21ad8f686..e104b3cee 100644 --- a/function/parameter_validation.go +++ b/function/parameter_validation.go @@ -1,16 +1,12 @@ package function -import ( - "github.com/hashicorp/terraform-plugin-framework/function/validator" -) - // ParameterWithBoolValidators is an optional interface on Parameter which // enables Bool validation support. type ParameterWithBoolValidators interface { Parameter // BoolValidators should return a list of Bool validators. - BoolValidators() []validator.Bool + BoolValidators() []BoolValidator } // ParameterWithInt64Validators is an optional interface on Parameter which @@ -19,7 +15,7 @@ type ParameterWithInt64Validators interface { Parameter // Int64Validators should return a list of Int64 validators. - Int64Validators() []validator.Int64 + Int64Validators() []Int64Validator } // ParameterWithFloat64Validators is an optional interface on Parameter which @@ -28,7 +24,7 @@ type ParameterWithFloat64Validators interface { Parameter // Float64Validators should return a list of Float64 validators. - Float64Validators() []validator.Float64 + Float64Validators() []Float64Validator } // ParameterWithDynamicValidators is an optional interface on Parameter which @@ -37,7 +33,7 @@ type ParameterWithDynamicValidators interface { Parameter // DynamicValidators should return a list of Dynamic validators. - DynamicValidators() []validator.Dynamic + DynamicValidators() []DynamicValidator } // ParameterWithListValidators is an optional interface on Parameter which @@ -46,7 +42,7 @@ type ParameterWithListValidators interface { Parameter // ListValidators should return a list of List validators. - ListValidators() []validator.List + ListValidators() []ListValidator } // ParameterWithMapValidators is an optional interface on Parameter which @@ -55,7 +51,7 @@ type ParameterWithMapValidators interface { Parameter // MapValidators should return a list of Map validators. - MapValidators() []validator.Map + MapValidators() []MapValidator } // ParameterWithNumberValidators is an optional interface on Parameter which @@ -64,7 +60,7 @@ type ParameterWithNumberValidators interface { Parameter // NumberValidators should return a list of Map validators. - NumberValidators() []validator.Number + NumberValidators() []NumberValidator } // ParameterWithObjectValidators is an optional interface on Parameter which @@ -73,7 +69,7 @@ type ParameterWithObjectValidators interface { Parameter // ObjectValidators should return a list of Object validators. - ObjectValidators() []validator.Object + ObjectValidators() []ObjectValidator } // ParameterWithSetValidators is an optional interface on Parameter which @@ -82,7 +78,7 @@ type ParameterWithSetValidators interface { Parameter // SetValidators should return a list of Set validators. - SetValidators() []validator.Set + SetValidators() []SetValidator } // ParameterWithStringValidators is an optional interface on Parameter which @@ -91,5 +87,5 @@ type ParameterWithStringValidators interface { Parameter // StringValidators should return a list of String validators. - StringValidators() []validator.String + StringValidators() []StringValidator } diff --git a/function/set_parameter.go b/function/set_parameter.go index 8888a6205..a69c4fb25 100644 --- a/function/set_parameter.go +++ b/function/set_parameter.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/fwtype" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -87,10 +86,10 @@ type SetParameter struct { // Validators is a list of set validators that should be applied to the // parameter. - Validators []validator.Set + Validators []SetValidator } -func (p SetParameter) SetValidators() []validator.Set { +func (p SetParameter) SetValidators() []SetValidator { return p.Validators } diff --git a/function/validator/set.go b/function/set_parameter_validator.go similarity index 65% rename from function/validator/set.go rename to function/set_parameter_validator.go index c29b8179e..812816405 100644 --- a/function/validator/set.go +++ b/function/set_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// Set is a function validator for types.Set parameters. -type Set interface { +// SetValidator is a function validator for types.Set parameters. +type SetValidator interface { - // ValidateSet should perform the validation. - ValidateSet(context.Context, SetRequest, *SetResponse) + // Validate should perform the validation. + Validate(context.Context, SetRequest, *SetResponse) } // SetRequest is a request for types.Set schema validation. @@ -27,5 +26,5 @@ type SetRequest struct { // SetResponse is a response to a SetRequest. type SetResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/function/string_parameter.go b/function/string_parameter.go index 9064a540f..0ed17193d 100644 --- a/function/string_parameter.go +++ b/function/string_parameter.go @@ -5,7 +5,6 @@ package function import ( "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -71,11 +70,11 @@ type StringParameter struct { // Validators is a list of string validators that should be applied to the // parameter. - Validators []validator.String + Validators []StringValidator } // StringValidators returns the string validators for the parameter. -func (p StringParameter) StringValidators() []validator.String { +func (p StringParameter) StringValidators() []StringValidator { return p.Validators } diff --git a/function/validator/string.go b/function/string_parameter_validator.go similarity index 70% rename from function/validator/string.go rename to function/string_parameter_validator.go index 4322f0cdc..91e72a4ba 100644 --- a/function/validator/string.go +++ b/function/string_parameter_validator.go @@ -1,17 +1,16 @@ -package validator +package function import ( "context" - "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/types" ) -// String is a function validator for types.String parameters. -type String interface { +// StringValidator is a function validator for types.String parameters. +type StringValidator interface { // ValidateString should perform the validation. - ValidateString(context.Context, StringRequest, *StringResponse) + Validate(context.Context, StringRequest, *StringResponse) } // StringRequest is a request for types.String schema validation. @@ -27,5 +26,5 @@ type StringRequest struct { // StringResponse is a response to a StringRequest. type StringResponse struct { // Error is a function error generated during validation of the Value. - Error *function.FuncError + Error *FuncError } diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 6c72b537b..934f76278 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -12,7 +12,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/function" - "github.com/hashicorp/terraform-plugin-framework/function/validator" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" @@ -167,12 +166,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def switch parameterWithValidators := parameter.(type) { case function.ParameterWithBoolValidators: for _, functionValidator := range parameterWithValidators.BoolValidators() { - req := validator.BoolRequest{ + req := function.BoolRequest{ ArgumentPosition: position, Value: attrValue.(types.Bool), } - resp := &validator.BoolResponse{} - functionValidator.ValidateBool(ctx, req, resp) + resp := &function.BoolResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -182,12 +181,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithDynamicValidators: for _, functionValidator := range parameterWithValidators.DynamicValidators() { - req := validator.DynamicRequest{ + req := function.DynamicRequest{ ArgumentPosition: position, Value: attrValue.(types.Dynamic), } - resp := &validator.DynamicResponse{} - functionValidator.ValidateDynamic(ctx, req, resp) + resp := &function.DynamicResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -197,12 +196,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithFloat64Validators: for _, functionValidator := range parameterWithValidators.Float64Validators() { - req := validator.Float64Request{ + req := function.Float64Request{ ArgumentPosition: position, Value: attrValue.(types.Float64), } - resp := &validator.Float64Response{} - functionValidator.ValidateFloat64(ctx, req, resp) + resp := &function.Float64Response{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -212,12 +211,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithInt64Validators: for _, functionValidator := range parameterWithValidators.Int64Validators() { - req := validator.Int64Request{ + req := function.Int64Request{ ArgumentPosition: position, Value: attrValue.(types.Int64), } - resp := &validator.Int64Response{} - functionValidator.ValidateInt64(ctx, req, resp) + resp := &function.Int64Response{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -227,12 +226,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithListValidators: for _, functionValidator := range parameterWithValidators.ListValidators() { - req := validator.ListRequest{ + req := function.ListRequest{ ArgumentPosition: position, Value: attrValue.(types.List), } - resp := &validator.ListResponse{} - functionValidator.ValidateList(ctx, req, resp) + resp := &function.ListResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -242,12 +241,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithMapValidators: for _, functionValidator := range parameterWithValidators.MapValidators() { - req := validator.MapRequest{ + req := function.MapRequest{ ArgumentPosition: position, Value: attrValue.(types.Map), } - resp := &validator.MapResponse{} - functionValidator.ValidateMap(ctx, req, resp) + resp := &function.MapResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -257,12 +256,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithNumberValidators: for _, functionValidator := range parameterWithValidators.NumberValidators() { - req := validator.NumberRequest{ + req := function.NumberRequest{ ArgumentPosition: position, Value: attrValue.(types.Number), } - resp := &validator.NumberResponse{} - functionValidator.ValidateNumber(ctx, req, resp) + resp := &function.NumberResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -272,12 +271,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithObjectValidators: for _, functionValidator := range parameterWithValidators.ObjectValidators() { - req := validator.ObjectRequest{ + req := function.ObjectRequest{ ArgumentPosition: position, Value: attrValue.(types.Object), } - resp := &validator.ObjectResponse{} - functionValidator.ValidateObject(ctx, req, resp) + resp := &function.ObjectResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -287,12 +286,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithSetValidators: for _, functionValidator := range parameterWithValidators.SetValidators() { - req := validator.SetRequest{ + req := function.SetRequest{ ArgumentPosition: position, Value: attrValue.(types.Set), } - resp := &validator.SetResponse{} - functionValidator.ValidateSet(ctx, req, resp) + resp := &function.SetResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -302,12 +301,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithStringValidators: for _, functionValidator := range parameterWithValidators.StringValidators() { - req := validator.StringRequest{ + req := function.StringRequest{ ArgumentPosition: position, Value: attrValue.(types.String), } - resp := &validator.StringResponse{} - functionValidator.ValidateString(ctx, req, resp) + resp := &function.StringResponse{} + functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, diff --git a/internal/testing/testvalidator/bool.go b/internal/testing/testvalidator/bool.go index f7acabfa7..310a15e52 100644 --- a/internal/testing/testvalidator/bool.go +++ b/internal/testing/testvalidator/bool.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Bool = &Bool{} +var ( + _ validator.Bool = &Bool{} + _ function.BoolValidator = &Bool{} +) // Declarative validator.Bool for unit testing. type Bool struct { @@ -17,6 +21,7 @@ type Bool struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateBoolMethod func(context.Context, validator.BoolRequest, *validator.BoolResponse) + ValidateMethod func(context.Context, function.BoolRequest, *function.BoolResponse) } // Description satisfies the validator.Bool interface. @@ -37,7 +42,7 @@ func (v Bool) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Bool interface. +// ValidateBool satisfies the validator.Bool interface. func (v Bool) ValidateBool(ctx context.Context, req validator.BoolRequest, resp *validator.BoolResponse) { if v.ValidateBoolMethod == nil { return @@ -45,3 +50,12 @@ func (v Bool) ValidateBool(ctx context.Context, req validator.BoolRequest, resp v.ValidateBoolMethod(ctx, req, resp) } + +// Validate satisfies the function.BoolValidator interface. +func (v Bool) Validate(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} From 3dac93f74ac59eae53b36d01307b181746d04c9d Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Fri, 29 Mar 2024 14:24:53 -0400 Subject: [PATCH 18/62] Add parameter unit tests --- function/bool_parameter_test.go | 44 +++++++++++++++++++++++ function/dynamic_parameter_test.go | 44 +++++++++++++++++++++++ function/float64_parameter_test.go | 44 +++++++++++++++++++++++ function/int64_parameter_test.go | 44 +++++++++++++++++++++++ function/list_parameter_test.go | 44 +++++++++++++++++++++++ function/map_parameter_test.go | 44 +++++++++++++++++++++++ function/number_parameter_test.go | 44 +++++++++++++++++++++++ function/object_parameter_test.go | 44 +++++++++++++++++++++++ function/set_parameter_test.go | 44 +++++++++++++++++++++++ function/string_parameter_test.go | 44 +++++++++++++++++++++++ internal/testing/testvalidator/dynamic.go | 18 ++++++++-- internal/testing/testvalidator/float64.go | 18 ++++++++-- internal/testing/testvalidator/int64.go | 18 ++++++++-- internal/testing/testvalidator/list.go | 18 ++++++++-- internal/testing/testvalidator/map.go | 18 ++++++++-- internal/testing/testvalidator/number.go | 18 ++++++++-- internal/testing/testvalidator/object.go | 18 ++++++++-- internal/testing/testvalidator/set.go | 18 ++++++++-- internal/testing/testvalidator/string.go | 18 ++++++++-- 19 files changed, 584 insertions(+), 18 deletions(-) diff --git a/function/bool_parameter_test.go b/function/bool_parameter_test.go index f82113cf7..86821c130 100644 --- a/function/bool_parameter_test.go +++ b/function/bool_parameter_test.go @@ -7,9 +7,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -240,3 +242,45 @@ func TestBoolParameterGetType(t *testing.T) { }) } } + +func TestBoolParameterBoolValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.BoolParameter + expected []function.BoolValidator + }{ + "unset": { + parameter: function.BoolParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.BoolParameter{ + Validators: []function.BoolValidator{}}, + expected: []function.BoolValidator{}, + }, + "Validators": { + parameter: function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{}, + }}, + expected: []function.BoolValidator{ + testvalidator.Bool{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.BoolValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/function/dynamic_parameter_test.go b/function/dynamic_parameter_test.go index a6e50c2b6..a6dddac90 100644 --- a/function/dynamic_parameter_test.go +++ b/function/dynamic_parameter_test.go @@ -7,9 +7,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -240,3 +242,45 @@ func TestDynamicParameterGetType(t *testing.T) { }) } } + +func TestDynamicParameterDynamicValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.DynamicParameter + expected []function.DynamicValidator + }{ + "unset": { + parameter: function.DynamicParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.DynamicParameter{ + Validators: []function.DynamicValidator{}}, + expected: []function.DynamicValidator{}, + }, + "Validators": { + parameter: function.DynamicParameter{ + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{}, + }}, + expected: []function.DynamicValidator{ + testvalidator.Dynamic{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.DynamicValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/function/float64_parameter_test.go b/function/float64_parameter_test.go index 479d06437..5db6d9f61 100644 --- a/function/float64_parameter_test.go +++ b/function/float64_parameter_test.go @@ -7,9 +7,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -240,3 +242,45 @@ func TestFloat64ParameterGetType(t *testing.T) { }) } } + +func TestFloat64ParameterFloat64Validators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.Float64Parameter + expected []function.Float64Validator + }{ + "unset": { + parameter: function.Float64Parameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.Float64Parameter{ + Validators: []function.Float64Validator{}}, + expected: []function.Float64Validator{}, + }, + "Validators": { + parameter: function.Float64Parameter{ + Validators: []function.Float64Validator{ + testvalidator.Float64{}, + }}, + expected: []function.Float64Validator{ + testvalidator.Float64{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.Float64Validators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/function/int64_parameter_test.go b/function/int64_parameter_test.go index 5422dcd69..07c566c6e 100644 --- a/function/int64_parameter_test.go +++ b/function/int64_parameter_test.go @@ -7,9 +7,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -240,3 +242,45 @@ func TestInt64ParameterGetType(t *testing.T) { }) } } + +func TestInt64ParameterInt64Validators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.Int64Parameter + expected []function.Int64Validator + }{ + "unset": { + parameter: function.Int64Parameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.Int64Parameter{ + Validators: []function.Int64Validator{}}, + expected: []function.Int64Validator{}, + }, + "Validators": { + parameter: function.Int64Parameter{ + Validators: []function.Int64Validator{ + testvalidator.Int64{}, + }}, + expected: []function.Int64Validator{ + testvalidator.Int64{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.Int64Validators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/function/list_parameter_test.go b/function/list_parameter_test.go index 3736a65c8..1757083ee 100644 --- a/function/list_parameter_test.go +++ b/function/list_parameter_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -257,6 +259,48 @@ func TestListParameterGetType(t *testing.T) { } } +func TestListParameterListValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.ListParameter + expected []function.ListValidator + }{ + "unset": { + parameter: function.ListParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.ListParameter{ + Validators: []function.ListValidator{}}, + expected: []function.ListValidator{}, + }, + "Validators": { + parameter: function.ListParameter{ + Validators: []function.ListValidator{ + testvalidator.List{}, + }}, + expected: []function.ListValidator{ + testvalidator.List{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.ListValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestListParameterValidateImplementation(t *testing.T) { t.Parallel() diff --git a/function/map_parameter_test.go b/function/map_parameter_test.go index 0992a5452..dcd351806 100644 --- a/function/map_parameter_test.go +++ b/function/map_parameter_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -257,6 +259,48 @@ func TestMapParameterGetType(t *testing.T) { } } +func TestMapParameterMapValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.MapParameter + expected []function.MapValidator + }{ + "unset": { + parameter: function.MapParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.MapParameter{ + Validators: []function.MapValidator{}}, + expected: []function.MapValidator{}, + }, + "Validators": { + parameter: function.MapParameter{ + Validators: []function.MapValidator{ + testvalidator.Map{}, + }}, + expected: []function.MapValidator{ + testvalidator.Map{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.MapValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestMapParameterValidateImplementation(t *testing.T) { t.Parallel() diff --git a/function/number_parameter_test.go b/function/number_parameter_test.go index dcc097c1e..ec41ba93b 100644 --- a/function/number_parameter_test.go +++ b/function/number_parameter_test.go @@ -7,9 +7,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -240,3 +242,45 @@ func TestNumberParameterGetType(t *testing.T) { }) } } + +func TestNumberParameterNumberValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.NumberParameter + expected []function.NumberValidator + }{ + "unset": { + parameter: function.NumberParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.NumberParameter{ + Validators: []function.NumberValidator{}}, + expected: []function.NumberValidator{}, + }, + "Validators": { + parameter: function.NumberParameter{ + Validators: []function.NumberValidator{ + testvalidator.Number{}, + }}, + expected: []function.NumberValidator{ + testvalidator.Number{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.NumberValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/function/object_parameter_test.go b/function/object_parameter_test.go index d2794e5e6..21abc0651 100644 --- a/function/object_parameter_test.go +++ b/function/object_parameter_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -265,6 +267,48 @@ func TestObjectParameterGetType(t *testing.T) { } } +func TestObjectParameterObjectValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.ObjectParameter + expected []function.ObjectValidator + }{ + "unset": { + parameter: function.ObjectParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.ObjectParameter{ + Validators: []function.ObjectValidator{}}, + expected: []function.ObjectValidator{}, + }, + "Validators": { + parameter: function.ObjectParameter{ + Validators: []function.ObjectValidator{ + testvalidator.Object{}, + }}, + expected: []function.ObjectValidator{ + testvalidator.Object{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.ObjectValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestObjectParameterValidateImplementation(t *testing.T) { t.Parallel() diff --git a/function/set_parameter_test.go b/function/set_parameter_test.go index d0fc4fa5d..ab5a9de9a 100644 --- a/function/set_parameter_test.go +++ b/function/set_parameter_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -257,6 +259,48 @@ func TestSetParameterGetType(t *testing.T) { } } +func TestSetParameterSetValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.SetParameter + expected []function.SetValidator + }{ + "unset": { + parameter: function.SetParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.SetParameter{ + Validators: []function.SetValidator{}}, + expected: []function.SetValidator{}, + }, + "Validators": { + parameter: function.SetParameter{ + Validators: []function.SetValidator{ + testvalidator.Set{}, + }}, + expected: []function.SetValidator{ + testvalidator.Set{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.SetValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + func TestSetParameterValidateImplementation(t *testing.T) { t.Parallel() diff --git a/function/string_parameter_test.go b/function/string_parameter_test.go index 1cf9bbcbf..29aacaf78 100644 --- a/function/string_parameter_test.go +++ b/function/string_parameter_test.go @@ -7,9 +7,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -240,3 +242,45 @@ func TestStringParameterGetType(t *testing.T) { }) } } + +func TestStringParameterStringValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + parameter function.StringParameter + expected []function.StringValidator + }{ + "unset": { + parameter: function.StringParameter{}, + expected: nil, + }, + "Validators - empty": { + parameter: function.StringParameter{ + Validators: []function.StringValidator{}}, + expected: []function.StringValidator{}, + }, + "Validators": { + parameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{}, + }}, + expected: []function.StringValidator{ + testvalidator.String{}, + }, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.parameter.StringValidators() + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} diff --git a/internal/testing/testvalidator/dynamic.go b/internal/testing/testvalidator/dynamic.go index 6be786569..9eb10d501 100644 --- a/internal/testing/testvalidator/dynamic.go +++ b/internal/testing/testvalidator/dynamic.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Dynamic = &Dynamic{} +var ( + _ validator.Dynamic = &Dynamic{} + _ function.DynamicValidator = &Dynamic{} +) // Declarative validator.Dynamic for unit testing. type Dynamic struct { @@ -17,6 +21,7 @@ type Dynamic struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateDynamicMethod func(context.Context, validator.DynamicRequest, *validator.DynamicResponse) + ValidateMethod func(context.Context, function.DynamicRequest, *function.DynamicResponse) } // Description satisfies the validator.Dynamic interface. @@ -37,7 +42,7 @@ func (v Dynamic) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Dynamic interface. +// ValidateDynamic satisfies the validator.Dynamic interface. func (v Dynamic) ValidateDynamic(ctx context.Context, req validator.DynamicRequest, resp *validator.DynamicResponse) { if v.ValidateDynamicMethod == nil { return @@ -45,3 +50,12 @@ func (v Dynamic) ValidateDynamic(ctx context.Context, req validator.DynamicReque v.ValidateDynamicMethod(ctx, req, resp) } + +// Validate satisfies the function.DynamicValidator interface. +func (v Dynamic) Validate(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/float64.go b/internal/testing/testvalidator/float64.go index 8ecdc2351..d209e8af9 100644 --- a/internal/testing/testvalidator/float64.go +++ b/internal/testing/testvalidator/float64.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Float64 = &Float64{} +var ( + _ validator.Float64 = &Float64{} + _ function.Float64Validator = &Float64{} +) // Declarative validator.Float64 for unit testing. type Float64 struct { @@ -17,6 +21,7 @@ type Float64 struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateFloat64Method func(context.Context, validator.Float64Request, *validator.Float64Response) + ValidateMethod func(context.Context, function.Float64Request, *function.Float64Response) } // Description satisfies the validator.Float64 interface. @@ -37,7 +42,7 @@ func (v Float64) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Float64 interface. +// ValidateFloat64 satisfies the validator.Float64 interface. func (v Float64) ValidateFloat64(ctx context.Context, req validator.Float64Request, resp *validator.Float64Response) { if v.ValidateFloat64Method == nil { return @@ -45,3 +50,12 @@ func (v Float64) ValidateFloat64(ctx context.Context, req validator.Float64Reque v.ValidateFloat64Method(ctx, req, resp) } + +// Validate satisfies the function.Float64Validator interface. +func (v Float64) Validate(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/int64.go b/internal/testing/testvalidator/int64.go index 94cbc5a68..cbb203a0e 100644 --- a/internal/testing/testvalidator/int64.go +++ b/internal/testing/testvalidator/int64.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Int64 = &Int64{} +var ( + _ validator.Int64 = &Int64{} + _ function.Int64Validator = &Int64{} +) // Declarative validator.Int64 for unit testing. type Int64 struct { @@ -17,6 +21,7 @@ type Int64 struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateInt64Method func(context.Context, validator.Int64Request, *validator.Int64Response) + ValidateMethod func(context.Context, function.Int64Request, *function.Int64Response) } // Description satisfies the validator.Int64 interface. @@ -37,7 +42,7 @@ func (v Int64) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Int64 interface. +// ValidateInt64 satisfies the validator.Int64 interface. func (v Int64) ValidateInt64(ctx context.Context, req validator.Int64Request, resp *validator.Int64Response) { if v.ValidateInt64Method == nil { return @@ -45,3 +50,12 @@ func (v Int64) ValidateInt64(ctx context.Context, req validator.Int64Request, re v.ValidateInt64Method(ctx, req, resp) } + +// Validate satisfies the function.Int64Validator interface. +func (v Int64) Validate(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/list.go b/internal/testing/testvalidator/list.go index d10901ba2..b85ff04b2 100644 --- a/internal/testing/testvalidator/list.go +++ b/internal/testing/testvalidator/list.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.List = &List{} +var ( + _ validator.List = &List{} + _ function.ListValidator = &List{} +) // Declarative validator.List for unit testing. type List struct { @@ -17,6 +21,7 @@ type List struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateListMethod func(context.Context, validator.ListRequest, *validator.ListResponse) + ValidateMethod func(context.Context, function.ListRequest, *function.ListResponse) } // Description satisfies the validator.List interface. @@ -37,7 +42,7 @@ func (v List) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.List interface. +// ValidateList satisfies the validator.List interface. func (v List) ValidateList(ctx context.Context, req validator.ListRequest, resp *validator.ListResponse) { if v.ValidateListMethod == nil { return @@ -45,3 +50,12 @@ func (v List) ValidateList(ctx context.Context, req validator.ListRequest, resp v.ValidateListMethod(ctx, req, resp) } + +// Validate satisfies the function.ListValidator interface. +func (v List) Validate(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/map.go b/internal/testing/testvalidator/map.go index 0eefe7325..d3203786e 100644 --- a/internal/testing/testvalidator/map.go +++ b/internal/testing/testvalidator/map.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Map = &Map{} +var ( + _ validator.Map = &Map{} + _ function.MapValidator = &Map{} +) // Declarative validator.Map for unit testing. type Map struct { @@ -17,6 +21,7 @@ type Map struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateMapMethod func(context.Context, validator.MapRequest, *validator.MapResponse) + ValidateMethod func(context.Context, function.MapRequest, *function.MapResponse) } // Description satisfies the validator.Map interface. @@ -37,7 +42,7 @@ func (v Map) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Map interface. +// ValidateMap satisfies the validator.Map interface. func (v Map) ValidateMap(ctx context.Context, req validator.MapRequest, resp *validator.MapResponse) { if v.ValidateMapMethod == nil { return @@ -45,3 +50,12 @@ func (v Map) ValidateMap(ctx context.Context, req validator.MapRequest, resp *va v.ValidateMapMethod(ctx, req, resp) } + +// Validate satisfies the function.MapValidator interface. +func (v Map) Validate(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/number.go b/internal/testing/testvalidator/number.go index 36bf8fa40..c8261f710 100644 --- a/internal/testing/testvalidator/number.go +++ b/internal/testing/testvalidator/number.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Number = &Number{} +var ( + _ validator.Number = &Number{} + _ function.NumberValidator = &Number{} +) // Declarative validator.Number for unit testing. type Number struct { @@ -17,6 +21,7 @@ type Number struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateNumberMethod func(context.Context, validator.NumberRequest, *validator.NumberResponse) + ValidateMethod func(context.Context, function.NumberRequest, *function.NumberResponse) } // Description satisfies the validator.Number interface. @@ -37,7 +42,7 @@ func (v Number) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Number interface. +// ValidateNumber satisfies the validator.Number interface. func (v Number) ValidateNumber(ctx context.Context, req validator.NumberRequest, resp *validator.NumberResponse) { if v.ValidateNumberMethod == nil { return @@ -45,3 +50,12 @@ func (v Number) ValidateNumber(ctx context.Context, req validator.NumberRequest, v.ValidateNumberMethod(ctx, req, resp) } + +// Validate satisfies the function.NumberValidator interface. +func (v Number) Validate(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/object.go b/internal/testing/testvalidator/object.go index 0625731ed..a55fa353b 100644 --- a/internal/testing/testvalidator/object.go +++ b/internal/testing/testvalidator/object.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Object = &Object{} +var ( + _ validator.Object = &Object{} + _ function.ObjectValidator = &Object{} +) // Declarative validator.Object for unit testing. type Object struct { @@ -17,6 +21,7 @@ type Object struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateObjectMethod func(context.Context, validator.ObjectRequest, *validator.ObjectResponse) + ValidateMethod func(context.Context, function.ObjectRequest, *function.ObjectResponse) } // Description satisfies the validator.Object interface. @@ -37,7 +42,7 @@ func (v Object) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Object interface. +// ValidateObject satisfies the validator.Object interface. func (v Object) ValidateObject(ctx context.Context, req validator.ObjectRequest, resp *validator.ObjectResponse) { if v.ValidateObjectMethod == nil { return @@ -45,3 +50,12 @@ func (v Object) ValidateObject(ctx context.Context, req validator.ObjectRequest, v.ValidateObjectMethod(ctx, req, resp) } + +// Validate satisfies the function.ObjectValidator interface. +func (v Object) Validate(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/set.go b/internal/testing/testvalidator/set.go index e383b9e33..c161b8c96 100644 --- a/internal/testing/testvalidator/set.go +++ b/internal/testing/testvalidator/set.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.Set = &Set{} +var ( + _ validator.Set = &Set{} + _ function.SetValidator = &Set{} +) // Declarative validator.Set for unit testing. type Set struct { @@ -17,6 +21,7 @@ type Set struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateSetMethod func(context.Context, validator.SetRequest, *validator.SetResponse) + ValidateMethod func(context.Context, function.SetRequest, *function.SetResponse) } // Description satisfies the validator.Set interface. @@ -37,7 +42,7 @@ func (v Set) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.Set interface. +// ValidateSet satisfies the validator.Set interface. func (v Set) ValidateSet(ctx context.Context, req validator.SetRequest, resp *validator.SetResponse) { if v.ValidateSetMethod == nil { return @@ -45,3 +50,12 @@ func (v Set) ValidateSet(ctx context.Context, req validator.SetRequest, resp *va v.ValidateSetMethod(ctx, req, resp) } + +// Validate satisfies the function.SetValidator interface. +func (v Set) Validate(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} diff --git a/internal/testing/testvalidator/string.go b/internal/testing/testvalidator/string.go index 304b27536..24b5f4f68 100644 --- a/internal/testing/testvalidator/string.go +++ b/internal/testing/testvalidator/string.go @@ -6,10 +6,14 @@ package testvalidator import ( "context" + "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) -var _ validator.String = &String{} +var ( + _ validator.String = &String{} + _ function.StringValidator = &String{} +) // Declarative validator.String for unit testing. type String struct { @@ -17,6 +21,7 @@ type String struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateStringMethod func(context.Context, validator.StringRequest, *validator.StringResponse) + ValidateMethod func(context.Context, function.StringRequest, *function.StringResponse) } // Description satisfies the validator.String interface. @@ -37,7 +42,7 @@ func (v String) MarkdownDescription(ctx context.Context) string { return v.MarkdownDescriptionMethod(ctx) } -// Validate satisfies the validator.String interface. +// ValidateString satisfies the validator.String interface. func (v String) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { if v.ValidateStringMethod == nil { return @@ -45,3 +50,12 @@ func (v String) ValidateString(ctx context.Context, req validator.StringRequest, v.ValidateStringMethod(ctx, req, resp) } + +// Validate satisfies the function.StringValidator interface. +func (v String) Validate(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + if v.ValidateMethod == nil { + return + } + + v.ValidateMethod(ctx, req, resp) +} From fb0d4fce1b74698668e98e95a4c867a27a8224c2 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Mon, 1 Apr 2024 18:12:53 -0400 Subject: [PATCH 19/62] Add parameter tests to arguments_data_test.go --- function/bool_parameter_validator.go | 2 +- function/dynamic_parameter_validator.go | 2 +- function/float64_parameter_validator.go | 2 +- function/int64_parameter_validator.go | 2 +- function/list_parameter_validator.go | 2 +- function/map_parameter_validator.go | 2 +- function/number_parameter_validator.go | 2 +- function/object_parameter_validator.go | 2 +- function/set_parameter_validator.go | 2 +- function/string_parameter_validator.go | 2 +- internal/fromproto5/arguments_data.go | 27 +- internal/fromproto5/arguments_data_test.go | 1284 +++++++++++++++++++- 12 files changed, 1302 insertions(+), 29 deletions(-) diff --git a/function/bool_parameter_validator.go b/function/bool_parameter_validator.go index dd91207ae..29112b468 100644 --- a/function/bool_parameter_validator.go +++ b/function/bool_parameter_validator.go @@ -17,7 +17,7 @@ type BoolValidator interface { type BoolRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Bool diff --git a/function/dynamic_parameter_validator.go b/function/dynamic_parameter_validator.go index 6b08adc14..89332d743 100644 --- a/function/dynamic_parameter_validator.go +++ b/function/dynamic_parameter_validator.go @@ -17,7 +17,7 @@ type DynamicValidator interface { type DynamicRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Dynamic diff --git a/function/float64_parameter_validator.go b/function/float64_parameter_validator.go index 66d2a7985..e723768d4 100644 --- a/function/float64_parameter_validator.go +++ b/function/float64_parameter_validator.go @@ -17,7 +17,7 @@ type Float64Validator interface { type Float64Request struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Float64 diff --git a/function/int64_parameter_validator.go b/function/int64_parameter_validator.go index 3c6526357..fe2c0914a 100644 --- a/function/int64_parameter_validator.go +++ b/function/int64_parameter_validator.go @@ -17,7 +17,7 @@ type Int64Validator interface { type Int64Request struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Int64 diff --git a/function/list_parameter_validator.go b/function/list_parameter_validator.go index d227c6cc4..0b3564be9 100644 --- a/function/list_parameter_validator.go +++ b/function/list_parameter_validator.go @@ -17,7 +17,7 @@ type ListValidator interface { type ListRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.List diff --git a/function/map_parameter_validator.go b/function/map_parameter_validator.go index 240cdda4a..982abe088 100644 --- a/function/map_parameter_validator.go +++ b/function/map_parameter_validator.go @@ -17,7 +17,7 @@ type MapValidator interface { type MapRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Map diff --git a/function/number_parameter_validator.go b/function/number_parameter_validator.go index 1dc486b75..2072eb953 100644 --- a/function/number_parameter_validator.go +++ b/function/number_parameter_validator.go @@ -17,7 +17,7 @@ type NumberValidator interface { type NumberRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Number diff --git a/function/object_parameter_validator.go b/function/object_parameter_validator.go index 68b287fee..cf3797d6e 100644 --- a/function/object_parameter_validator.go +++ b/function/object_parameter_validator.go @@ -17,7 +17,7 @@ type ObjectValidator interface { type ObjectRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Object diff --git a/function/set_parameter_validator.go b/function/set_parameter_validator.go index 812816405..1bfbc92b0 100644 --- a/function/set_parameter_validator.go +++ b/function/set_parameter_validator.go @@ -17,7 +17,7 @@ type SetValidator interface { type SetRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.Set diff --git a/function/string_parameter_validator.go b/function/string_parameter_validator.go index 91e72a4ba..dd8a2f797 100644 --- a/function/string_parameter_validator.go +++ b/function/string_parameter_validator.go @@ -17,7 +17,7 @@ type StringValidator interface { type StringRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. - ArgumentPosition int + ArgumentPosition int64 // Value contains the value of the argument for validation. Value types.String diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 934f76278..4ee8fd90a 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -59,9 +59,10 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) - if funcError != nil { - return function.NewArgumentsData(nil), funcError - } + //TODO: ask about the error handling here + //if funcError != nil { + // return function.NewArgumentsData(nil), funcError + //} parameterType := parameter.GetType() @@ -167,7 +168,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithBoolValidators: for _, functionValidator := range parameterWithValidators.BoolValidators() { req := function.BoolRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Bool), } resp := &function.BoolResponse{} @@ -182,7 +183,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithDynamicValidators: for _, functionValidator := range parameterWithValidators.DynamicValidators() { req := function.DynamicRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Dynamic), } resp := &function.DynamicResponse{} @@ -197,7 +198,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithFloat64Validators: for _, functionValidator := range parameterWithValidators.Float64Validators() { req := function.Float64Request{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Float64), } resp := &function.Float64Response{} @@ -212,7 +213,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithInt64Validators: for _, functionValidator := range parameterWithValidators.Int64Validators() { req := function.Int64Request{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Int64), } resp := &function.Int64Response{} @@ -227,7 +228,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithListValidators: for _, functionValidator := range parameterWithValidators.ListValidators() { req := function.ListRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.List), } resp := &function.ListResponse{} @@ -242,7 +243,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithMapValidators: for _, functionValidator := range parameterWithValidators.MapValidators() { req := function.MapRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Map), } resp := &function.MapResponse{} @@ -257,7 +258,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithNumberValidators: for _, functionValidator := range parameterWithValidators.NumberValidators() { req := function.NumberRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Number), } resp := &function.NumberResponse{} @@ -272,7 +273,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithObjectValidators: for _, functionValidator := range parameterWithValidators.ObjectValidators() { req := function.ObjectRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Object), } resp := &function.ObjectResponse{} @@ -287,7 +288,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithSetValidators: for _, functionValidator := range parameterWithValidators.SetValidators() { req := function.SetRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.Set), } resp := &function.SetResponse{} @@ -302,7 +303,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def case function.ParameterWithStringValidators: for _, functionValidator := range parameterWithValidators.StringValidators() { req := function.StringRequest{ - ArgumentPosition: position, + ArgumentPosition: pos, Value: attrValue.(types.String), } resp := &function.StringResponse{} diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index b23d231d9..dcf2dad96 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -5,6 +5,7 @@ package fromproto5_test import ( "context" + "math/big" "testing" "github.com/google/go-cmp/cmp" @@ -15,6 +16,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -86,8 +89,7 @@ func TestArgumentsData(t *testing.T) { }, expected: function.ArgumentsData{}, expectedFuncError: function.NewArgumentFuncError( - 0, - "Unable to Convert Function Argument: "+ + 0, "Unable to Convert Function Argument: "+ "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ @@ -142,8 +144,7 @@ func TestArgumentsData(t *testing.T) { }, expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( - 0, - "Error Diagnostic: This is an error.", + 0, "Error Diagnostic: This is an error.", ), }, "parameters-one-TypeWithParameterValidation-error": { @@ -159,8 +160,7 @@ func TestArgumentsData(t *testing.T) { }, expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( - 0, - "This is a function error", + 0, "This is a function error", ), }, "parameters-one-TypeWithValidation-warning": { @@ -434,3 +434,1275 @@ func TestArgumentsData(t *testing.T) { }) } } + +func TestArgumentsData_ParameterValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + input []*tfprotov5.DynamicValue + definition function.Definition + expected function.ArgumentsData + expectedFuncError *function.FuncError + }{ + "bool-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + }, + "bool-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "bool-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "dynamic-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(true)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + }, + "dynamic-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "dynamic-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "float64-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(1.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + }, + "float64-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(2.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "float64-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(2.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(3.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "int64-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(1) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + }, + "int64-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(2) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "int64-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(2) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(3) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "list-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "list-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "list-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "map-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + }, + "map-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "map-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key1": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "number-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(1)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewNumberValue(big.NewFloat(1)), + }), + }, + "number-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(2)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewNumberValue(big.NewFloat(1)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "number-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(2)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(3)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewNumberValue(big.NewFloat(1)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "object-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + }, + "object-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "object-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute1": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute1": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "set-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "set-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "set-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "string-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewStringValue("true"), + }), + }, + "string-parameter-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewStringValue("true"), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "string-parameter-Validators-multiple-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewStringValue("true"), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "multiple-parameter-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + basetypes.NewStringValue("true"), + }), + }, + "multiple-parameter-Validators-errors": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: bool validator error.", + ) + } + }, + }, + }, + }, + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + basetypes.NewStringValue("true"), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(0, "Error Diagnostic: bool validator error."), + function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), + ), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, diags := fromproto5.ArgumentsData(context.Background(), testCase.input, testCase.definition) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + + if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { + t.Errorf("unexpected diagnostics difference: %s", diff) + } + }) + } +} + +func createListValue(elementType attr.Type, elements []attr.Value) attr.Value { + list, _ := basetypes.NewListValue(elementType, elements) + return list +} + +func createMapValue(elementType attr.Type, elements map[string]attr.Value) attr.Value { + mapVal, _ := basetypes.NewMapValue(elementType, elements) + return mapVal +} + +func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) attr.Value { + object, _ := basetypes.NewObjectValue(attributeTypes, attributes) + return object +} + +func createSetValue(elementType attr.Type, elements []attr.Value) attr.Value { + list, _ := basetypes.NewSetValue(elementType, elements) + return list +} + +func createDynamicValue(value tftypes.Value) *tfprotov5.DynamicValue { + dynamicVal, _ := tfprotov5.NewDynamicValue(tftypes.DynamicPseudoType, value) + return &dynamicVal +} From bab78d48240ecd65b23d67ce0681ba3e68823b73 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 2 Apr 2024 15:07:04 +0100 Subject: [PATCH 20/62] Add Equal() methods to ListValueWithValidateAttributeWarning and MapValueWithValidateAttributeWarning --- .../testing/testtypes/listwithvalidateattribute.go | 10 ++++++++++ internal/testing/testtypes/mapwithvalidateattribute.go | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/internal/testing/testtypes/listwithvalidateattribute.go b/internal/testing/testtypes/listwithvalidateattribute.go index f0f95a4e7..891d8ed68 100644 --- a/internal/testing/testtypes/listwithvalidateattribute.go +++ b/internal/testing/testtypes/listwithvalidateattribute.go @@ -70,6 +70,16 @@ type ListValueWithValidateAttributeWarning struct { types.List } +func (v ListValueWithValidateAttributeWarning) Equal(o attr.Value) bool { + other, ok := o.(ListValueWithValidateAttributeWarning) + + if !ok { + return false + } + + return v.List.Equal(other.List) +} + func (v ListValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) } diff --git a/internal/testing/testtypes/mapwithvalidateattribute.go b/internal/testing/testtypes/mapwithvalidateattribute.go index b33076873..8ee49a02d 100644 --- a/internal/testing/testtypes/mapwithvalidateattribute.go +++ b/internal/testing/testtypes/mapwithvalidateattribute.go @@ -70,6 +70,16 @@ type MapValueWithValidateAttributeWarning struct { types.Map } +func (v MapValueWithValidateAttributeWarning) Equal(o attr.Value) bool { + other, ok := o.(MapValueWithValidateAttributeWarning) + + if !ok { + return false + } + + return v.Map.Equal(other.Map) +} + func (v MapValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) } From 50c673af9882bcbefd532880dd36ebe2b2c131b9 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 2 Apr 2024 15:10:19 +0100 Subject: [PATCH 21/62] Adding switch statements to reflect package FromMap() function to handle ValidateableAttribute assertions --- internal/reflect/map.go | 105 +++++++++++++---- internal/reflect/map_test.go | 216 ++++++++++++++++++++++++++++++++++- 2 files changed, 298 insertions(+), 23 deletions(-) diff --git a/internal/reflect/map.go b/internal/reflect/map.go index 57c3d5a1b..602061d7f 100644 --- a/internal/reflect/map.go +++ b/internal/reflect/map.go @@ -104,15 +104,6 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu if val.IsNil() { tfVal := tftypes.NewValue(tfType, nil) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - - if diags.HasError() { - return nil, diags - } - } - attrVal, err := typ.ValueFromTerraform(ctx, tfVal) if err != nil { @@ -124,6 +115,33 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu return nil, diags } + switch t := attrVal.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + + if diags.HasError() { + return nil, diags + } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + + if diags.HasError() { + return nil, diags + } + } + } + return attrVal, diags } @@ -139,24 +157,49 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu ) return nil, diags } - val, valDiags := FromValue(ctx, elemType, val.MapIndex(key).Interface(), path.AtMapKey(key.String())) + + mapKeyPath := path.AtMapKey(key.String()) + + // If the element implements xattr.ValidateableAttribute, or xattr.TypeWithValidate, + // and the element does not validate then diagnostics will be added here and returned + // before reaching the switch statement below. + val, valDiags := FromValue(ctx, elemType, val.MapIndex(key).Interface(), mapKeyPath) diags.Append(valDiags...) if diags.HasError() { return nil, diags } + tfVal, err := val.ToTerraformValue(ctx) if err != nil { return nil, append(diags, toTerraformValueErrorDiag(err, path)) } - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := elemType.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path.AtMapKey(key.String()))...) + switch t := val.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: mapKeyPath, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := elemType.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, mapKeyPath)...) + + if diags.HasError() { + return nil, diags + } + } } tfElems[key.String()] = tfVal @@ -169,15 +212,6 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu tfVal := tftypes.NewValue(tfType, tfElems) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - - if diags.HasError() { - return nil, diags - } - } - attrVal, err := typ.ValueFromTerraform(ctx, tfVal) if err != nil { @@ -189,5 +223,32 @@ func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Valu return nil, diags } + switch t := attrVal.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + + if diags.HasError() { + return nil, diags + } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + + if diags.HasError() { + return nil, diags + } + } + } + return attrVal, diags } diff --git a/internal/reflect/map_test.go b/internal/reflect/map_test.go index 498c0de4c..4d57b451f 100644 --- a/internal/reflect/map_test.go +++ b/internal/reflect/map_test.go @@ -8,10 +8,15 @@ import ( "reflect" "testing" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" refl "github.com/hashicorp/terraform-plugin-framework/internal/reflect" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" ) func TestReflectMap_string(t *testing.T) { @@ -46,3 +51,212 @@ func TestReflectMap_string(t *testing.T) { } } } + +func TestFromMap(t *testing.T) { + t.Parallel() + + var m map[string]string + + testCases := map[string]struct { + typ attr.TypeWithElementType + val reflect.Value + expected attr.Value + expectedDiags diag.Diagnostics + }{ + "null": { + typ: types.MapType{ + ElemType: types.StringType, + }, + val: reflect.ValueOf(m), + expected: types.MapNull(types.StringType), + }, + "nullWithValidateError": { + typ: testtypes.MapTypeWithValidateError{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(m), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "nullWithValidateAttributeError": { + typ: testtypes.MapTypeWithValidateAttributeError{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(m), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "nullWithValidateWarning": { + typ: testtypes.MapTypeWithValidateWarning{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(m), + expected: types.MapNull(types.StringType), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + "nullWithValidateAttributeWarning": { + typ: testtypes.MapTypeWithValidateAttributeWarning{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(m), + expected: testtypes.MapValueWithValidateAttributeWarning{ + Map: types.MapNull(types.StringType), + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + "map": { + typ: types.MapType{ElemType: types.StringType}, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expected: types.MapValueMust(types.StringType, map[string]attr.Value{ + "one": types.StringValue("a"), + }), + }, + "mapElemWithValidateError": { + typ: types.MapType{ + ElemType: testtypes.StringTypeWithValidateError{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty().AtMapKey("one")), + }, + }, + "mapElemWithValidateAttributeError": { + typ: types.MapType{ + ElemType: testtypes.StringTypeWithValidateAttributeError{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty().AtMapKey("one")), + }, + }, + "mapElemWithValidateWarning": { + typ: types.MapType{ + ElemType: testtypes.StringTypeWithValidateWarning{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expected: types.MapValueMust(testtypes.StringTypeWithValidateWarning{}, map[string]attr.Value{ + "one": testtypes.String{ + InternalString: types.StringValue("a"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty().AtMapKey("one")), + }, + }, + "mapElemWithValidateAttributeWarning": { + typ: types.MapType{ + ElemType: testtypes.StringTypeWithValidateAttributeWarning{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expected: types.MapValueMust(testtypes.StringTypeWithValidateAttributeWarning{}, map[string]attr.Value{ + "one": testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("a"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty().AtMapKey("one")), + }, + }, + "mapWithValidateError": { + typ: testtypes.MapTypeWithValidateError{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "mapWithValidateAttributeError": { + typ: testtypes.MapTypeWithValidateAttributeError{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "mapWithValidateWarning": { + typ: testtypes.MapTypeWithValidateWarning{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expected: types.MapValueMust( + types.StringType, + map[string]attr.Value{ + "one": types.StringValue("a"), + }, + ), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + "listWithValidateAttributeWarning": { + typ: testtypes.MapTypeWithValidateAttributeWarning{ + MapType: types.MapType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(map[string]string{"one": "a"}), + expected: testtypes.MapValueWithValidateAttributeWarning{ + Map: types.MapValueMust( + types.StringType, + map[string]attr.Value{ + "one": types.StringValue("a"), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + } + + for name, tc := range testCases { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, diags := refl.FromMap(context.Background(), tc.typ, tc.val, path.Empty()) + + if diff := cmp.Diff(diags, tc.expectedDiags); diff != "" { + t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) + } + + if diff := cmp.Diff(got, tc.expected); diff != "" { + t.Errorf("unexpected result (+wanted, -got): %s", diff) + } + }) + } +} From e0017b0bce3520c8e096d92df148da7316168407 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 2 Apr 2024 15:13:38 +0100 Subject: [PATCH 22/62] Adding switch statements to reflect package FromInt(), FromUint(), FromFloat(), FromBigFloat(), and FromBigInt() functions to handle ValidateableAttribute assertions --- internal/reflect/number.go | 160 ++++++++++++++---- internal/reflect/number_test.go | 100 +++++++++++ .../testtypes/numberwithvalidateattribute.go | 154 +++++++++++++++++ 3 files changed, 379 insertions(+), 35 deletions(-) create mode 100644 internal/testing/testtypes/numberwithvalidateattribute.go diff --git a/internal/reflect/number.go b/internal/reflect/number.go index c467e50f0..c4983be64 100644 --- a/internal/reflect/number.go +++ b/internal/reflect/number.go @@ -179,18 +179,36 @@ func FromInt(ctx context.Context, typ attr.Type, val int64, path path.Path) (att } tfNum := tftypes.NewValue(tftypes.Number, val) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) + num, err := typ.ValueFromTerraform(ctx, tfNum) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := num.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) - num, err := typ.ValueFromTerraform(ctx, tfNum) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } return num, diags @@ -207,18 +225,36 @@ func FromUint(ctx context.Context, typ attr.Type, val uint64, path path.Path) (a } tfNum := tftypes.NewValue(tftypes.Number, val) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) + num, err := typ.ValueFromTerraform(ctx, tfNum) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := num.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) - num, err := typ.ValueFromTerraform(ctx, tfNum) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } return num, diags @@ -235,18 +271,36 @@ func FromFloat(ctx context.Context, typ attr.Type, val float64, path path.Path) } tfNum := tftypes.NewValue(tftypes.Number, val) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) + num, err := typ.ValueFromTerraform(ctx, tfNum) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := num.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) - num, err := typ.ValueFromTerraform(ctx, tfNum) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } return num, diags @@ -263,18 +317,36 @@ func FromBigFloat(ctx context.Context, typ attr.Type, val *big.Float, path path. } tfNum := tftypes.NewValue(tftypes.Number, val) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) + num, err := typ.ValueFromTerraform(ctx, tfNum) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := num.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) - num, err := typ.ValueFromTerraform(ctx, tfNum) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } return num, diags @@ -292,18 +364,36 @@ func FromBigInt(ctx context.Context, typ attr.Type, val *big.Int, path path.Path } tfNum := tftypes.NewValue(tftypes.Number, fl) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) + num, err := typ.ValueFromTerraform(ctx, tfNum) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := num.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfNum, path)...) - num, err := typ.ValueFromTerraform(ctx, tfNum) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } return num, diags diff --git a/internal/reflect/number_test.go b/internal/reflect/number_test.go index 143733328..5c13d45b2 100644 --- a/internal/reflect/number_test.go +++ b/internal/reflect/number_test.go @@ -737,6 +737,19 @@ func TestFromInt(t *testing.T) { testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + val: 1, + typ: testtypes.NumberTypeWithValidateAttributeWarning{}, + expected: testtypes.NumberValueWithValidateAttributeWarning{ + InternalNumber: testtypes.Number{ + Number: types.NumberValue(big.NewFloat(1)), + CreatedBy: testtypes.NumberTypeWithValidateWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, "WithValidateError": { val: 1, typ: testtypes.NumberTypeWithValidateError{}, @@ -744,6 +757,13 @@ func TestFromInt(t *testing.T) { testtypes.TestErrorDiagnostic(path.Empty()), }, }, + "WithValidateAttributeError": { + val: 1, + typ: testtypes.NumberTypeWithValidateAttributeError{}, + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, } for name, tc := range cases { @@ -793,6 +813,19 @@ func TestFromUint(t *testing.T) { testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + val: 1, + typ: testtypes.NumberTypeWithValidateAttributeWarning{}, + expected: testtypes.NumberValueWithValidateAttributeWarning{ + InternalNumber: testtypes.Number{ + Number: types.NumberValue(big.NewFloat(1)), + CreatedBy: testtypes.NumberTypeWithValidateWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, "WithValidateError": { val: 1, typ: testtypes.NumberTypeWithValidateError{}, @@ -800,6 +833,13 @@ func TestFromUint(t *testing.T) { testtypes.TestErrorDiagnostic(path.Empty()), }, }, + "WithValidateAttributeError": { + val: 1, + typ: testtypes.NumberTypeWithValidateAttributeError{}, + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, } for name, tc := range cases { @@ -854,6 +894,19 @@ func TestFromFloat(t *testing.T) { testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + val: 1, + typ: testtypes.NumberTypeWithValidateAttributeWarning{}, + expected: testtypes.NumberValueWithValidateAttributeWarning{ + InternalNumber: testtypes.Number{ + Number: types.NumberValue(big.NewFloat(1)), + CreatedBy: testtypes.NumberTypeWithValidateWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, "WithValidateError": { val: 1, typ: testtypes.NumberTypeWithValidateError{}, @@ -861,6 +914,13 @@ func TestFromFloat(t *testing.T) { testtypes.TestErrorDiagnostic(path.Empty()), }, }, + "WithValidateAttributeError": { + val: 1, + typ: testtypes.NumberTypeWithValidateAttributeError{}, + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, } for name, tc := range cases { @@ -915,6 +975,19 @@ func TestFromBigFloat(t *testing.T) { testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + val: big.NewFloat(1), + typ: testtypes.NumberTypeWithValidateAttributeWarning{}, + expected: testtypes.NumberValueWithValidateAttributeWarning{ + InternalNumber: testtypes.Number{ + Number: types.NumberValue(big.NewFloat(1)), + CreatedBy: testtypes.NumberTypeWithValidateWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, "WithValidateError": { val: big.NewFloat(1), typ: testtypes.NumberTypeWithValidateError{}, @@ -922,6 +995,13 @@ func TestFromBigFloat(t *testing.T) { testtypes.TestErrorDiagnostic(path.Empty()), }, }, + "WithValidateAttributeError": { + val: big.NewFloat(1), + typ: testtypes.NumberTypeWithValidateAttributeError{}, + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, } for name, tc := range cases { @@ -971,6 +1051,19 @@ func TestFromBigInt(t *testing.T) { testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + val: big.NewInt(1), + typ: testtypes.NumberTypeWithValidateAttributeWarning{}, + expected: testtypes.NumberValueWithValidateAttributeWarning{ + InternalNumber: testtypes.Number{ + Number: types.NumberValue(big.NewFloat(1)), + CreatedBy: testtypes.NumberTypeWithValidateWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, "WithValidateError": { val: big.NewInt(1), typ: testtypes.NumberTypeWithValidateError{}, @@ -978,6 +1071,13 @@ func TestFromBigInt(t *testing.T) { testtypes.TestErrorDiagnostic(path.Empty()), }, }, + "WithValidateAttributeError": { + val: big.NewInt(1), + typ: testtypes.NumberTypeWithValidateAttributeError{}, + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, } for name, tc := range cases { diff --git a/internal/testing/testtypes/numberwithvalidateattribute.go b/internal/testing/testtypes/numberwithvalidateattribute.go new file mode 100644 index 000000000..09067e74f --- /dev/null +++ b/internal/testing/testtypes/numberwithvalidateattribute.go @@ -0,0 +1,154 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" +) + +type NumberTypeWithValidateAttributeError struct { + NumberType +} + +func (t NumberTypeWithValidateAttributeError) Equal(o attr.Type) bool { + other, ok := o.(NumberTypeWithValidateAttributeError) + if !ok { + return false + } + return t == other +} + +func (t NumberTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.NumberType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newNumber, ok := val.(Number) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", val) + } + + newNumber.CreatedBy = t + + return NumberValueWithValidateAttributeError{ + InternalNumber: newNumber, + }, nil +} + +var _ xattr.ValidateableAttribute = NumberValueWithValidateAttributeError{} + +type NumberValueWithValidateAttributeError struct { + InternalNumber Number +} + +func (v NumberValueWithValidateAttributeError) Type(ctx context.Context) attr.Type { + return v.InternalNumber.Type(ctx) +} + +func (v NumberValueWithValidateAttributeError) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + return v.InternalNumber.ToTerraformValue(ctx) +} + +func (v NumberValueWithValidateAttributeError) Equal(value attr.Value) bool { + other, ok := value.(NumberValueWithValidateAttributeError) + + if !ok { + return false + } + + return v == other +} + +func (v NumberValueWithValidateAttributeError) IsNull() bool { + return v.InternalNumber.IsNull() +} + +func (v NumberValueWithValidateAttributeError) IsUnknown() bool { + return v.InternalNumber.IsUnknown() +} + +func (v NumberValueWithValidateAttributeError) String() string { + return v.InternalNumber.String() +} + +func (v NumberValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) +} + +type NumberTypeWithValidateAttributeWarning struct { + NumberType +} + +func (t NumberTypeWithValidateAttributeWarning) Equal(o attr.Type) bool { + other, ok := o.(NumberTypeWithValidateAttributeWarning) + if !ok { + return false + } + return t == other +} + +func (t NumberTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.NumberType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newNumber, ok := val.(Number) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", val) + } + + newNumber.CreatedBy = t + + return NumberValueWithValidateAttributeWarning{ + InternalNumber: newNumber, + }, nil +} + +var _ xattr.ValidateableAttribute = NumberValueWithValidateAttributeWarning{} + +type NumberValueWithValidateAttributeWarning struct { + InternalNumber Number +} + +func (v NumberValueWithValidateAttributeWarning) Type(ctx context.Context) attr.Type { + return v.InternalNumber.Type(ctx) +} + +func (v NumberValueWithValidateAttributeWarning) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + return v.InternalNumber.ToTerraformValue(ctx) +} + +func (v NumberValueWithValidateAttributeWarning) Equal(value attr.Value) bool { + other, ok := value.(NumberValueWithValidateAttributeWarning) + + if !ok { + return false + } + + return v.InternalNumber.Number.Equal(other.InternalNumber.Number) +} + +func (v NumberValueWithValidateAttributeWarning) IsNull() bool { + return v.InternalNumber.IsNull() +} + +func (v NumberValueWithValidateAttributeWarning) IsUnknown() bool { + return v.InternalNumber.IsUnknown() +} + +func (v NumberValueWithValidateAttributeWarning) String() string { + return v.InternalNumber.String() +} + +func (v NumberValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) +} From 1d2c768ca868e88aba033c1151ff82ad9f300c21 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 2 Apr 2024 15:14:39 +0100 Subject: [PATCH 23/62] Adding switch statements to reflect package FromPointer() function to handle ValidateableAttribute assertions --- internal/reflect/pointer.go | 36 ++++++++++++++++++++++++-------- internal/reflect/pointer_test.go | 27 +++++++++++++++++++++--- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/internal/reflect/pointer.go b/internal/reflect/pointer.go index 65be2b841..d9d162068 100644 --- a/internal/reflect/pointer.go +++ b/internal/reflect/pointer.go @@ -94,15 +94,6 @@ func FromPointer(ctx context.Context, typ attr.Type, value reflect.Value, path p if value.IsNil() { tfVal := tftypes.NewValue(typ.TerraformType(ctx), nil) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - - if diags.HasError() { - return nil, diags - } - } - attrVal, err := typ.ValueFromTerraform(ctx, tfVal) if err != nil { @@ -114,6 +105,33 @@ func FromPointer(ctx context.Context, typ attr.Type, value reflect.Value, path p return nil, diags } + switch t := attrVal.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + + if diags.HasError() { + return nil, diags + } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + + if diags.HasError() { + return nil, diags + } + } + } + return attrVal, diags } diff --git a/internal/reflect/pointer_test.go b/internal/reflect/pointer_test.go index 2e9643562..fdc1ddd71 100644 --- a/internal/reflect/pointer_test.go +++ b/internal/reflect/pointer_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" refl "github.com/hashicorp/terraform-plugin-framework/internal/reflect" @@ -120,22 +121,42 @@ func TestFromPointer(t *testing.T) { }, "WithValidateError": { typ: testtypes.StringTypeWithValidateError{}, - val: reflect.ValueOf(strPtr("hello, world")), + val: reflect.ValueOf(new(*string)), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "WithValidateAttributeError": { + typ: testtypes.StringTypeWithValidateAttributeError{}, + val: reflect.ValueOf(new(*string)), expectedDiags: diag.Diagnostics{ testtypes.TestErrorDiagnostic(path.Empty()), }, }, "WithValidateWarning": { typ: testtypes.StringTypeWithValidateWarning{}, - val: reflect.ValueOf(strPtr("hello, world")), + val: reflect.ValueOf(new(*string)), expected: testtypes.String{ - InternalString: types.StringValue("hello, world"), + InternalString: types.StringNull(), CreatedBy: testtypes.StringTypeWithValidateWarning{}, }, expectedDiags: diag.Diagnostics{ testtypes.TestWarningDiagnostic(path.Empty()), }, }, + "WithValidateAttributeWarning": { + typ: testtypes.StringTypeWithValidateAttributeWarning{}, + val: reflect.ValueOf(new(*string)), + expected: testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringNull(), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, } for name, tc := range testCases { From 12dcc5c3d12d1033942868f85ac5054550b6531a Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 2 Apr 2024 15:15:55 +0100 Subject: [PATCH 24/62] Adding switch statements to reflect package FromSlice() function to handle ValidateableAttribute assertions --- internal/reflect/slice.go | 128 +++++++++-- internal/reflect/slice_test.go | 406 +++++++++++++++++++++++++++++++++ 2 files changed, 510 insertions(+), 24 deletions(-) create mode 100644 internal/reflect/slice_test.go diff --git a/internal/reflect/slice.go b/internal/reflect/slice.go index 0dd438005..794b4ef98 100644 --- a/internal/reflect/slice.go +++ b/internal/reflect/slice.go @@ -186,15 +186,6 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. if val.IsNil() { tfVal := tftypes.NewValue(tfType, nil) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - - if diags.HasError() { - return nil, diags - } - } - attrVal, err := typ.ValueFromTerraform(ctx, tfVal) if err != nil { @@ -206,6 +197,33 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. return nil, diags } + switch t := attrVal.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + + if diags.HasError() { + return nil, diags + } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + + if diags.HasError() { + return nil, diags + } + } + } + return attrVal, diags } @@ -222,6 +240,9 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. // debugging purposes, then correct the path afterwards. valPath := path.AtListIndex(i) + // If the element implements xattr.ValidateableAttribute, or xattr.TypeWithValidate, + // and the element does not validate then diagnostics will be added here and returned + // before reaching the switch statement below. val, valDiags := FromValue(ctx, elemType, val.Index(i).Interface(), valPath) diags.Append(valDiags...) @@ -238,12 +259,31 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. valPath = path.AtSetValue(val) } - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := elemType.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, valPath)...) + switch t := val.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: valPath, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + if diags.HasError() { return nil, diags } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := elemType.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, valPath)...) + + if diags.HasError() { + return nil, diags + } + } } tfElems = append(tfElems, tfVal) @@ -294,6 +334,9 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. for i := 0; i < val.Len(); i++ { valPath := path.AtTupleIndex(i) + // If the element implements xattr.ValidateableAttribute, or xattr.TypeWithValidate, + // and the element does not validate then diagnostics will be added here and returned + // before reaching the switch statement below. val, valDiags := FromValue(ctx, elemAttrType, val.Index(i).Interface(), valPath) diags.Append(valDiags...) @@ -306,12 +349,31 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. return nil, append(diags, toTerraformValueErrorDiag(err, path)) } - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := elemAttrType.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, valPath)...) + switch t := val.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: valPath, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + if diags.HasError() { return nil, diags } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := elemAttrType.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, valPath)...) + + if diags.HasError() { + return nil, diags + } + } } tfElems = append(tfElems, tfVal) @@ -333,15 +395,6 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. tfVal := tftypes.NewValue(tfType, tfElems) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - - if diags.HasError() { - return nil, diags - } - } - attrVal, err := typ.ValueFromTerraform(ctx, tfVal) if err != nil { @@ -353,5 +406,32 @@ func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path path. return nil, diags } + switch t := attrVal.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) + + if diags.HasError() { + return nil, diags + } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + + if diags.HasError() { + return nil, diags + } + } + } + return attrVal, diags } diff --git a/internal/reflect/slice_test.go b/internal/reflect/slice_test.go new file mode 100644 index 000000000..41a8daa09 --- /dev/null +++ b/internal/reflect/slice_test.go @@ -0,0 +1,406 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package reflect_test + +import ( + "context" + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + refl "github.com/hashicorp/terraform-plugin-framework/internal/reflect" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func TestFromSlice(t *testing.T) { + t.Parallel() + + var s []string + + testCases := map[string]struct { + typ attr.Type + val reflect.Value + expected attr.Value + expectedDiags diag.Diagnostics + }{ + "null": { + typ: types.ListType{ + ElemType: types.StringType, + }, + val: reflect.ValueOf(s), + expected: types.ListNull(types.StringType), + }, + "nullWithValidateError": { + typ: testtypes.ListTypeWithValidateError{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(s), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "nullWithValidateAttributeError": { + typ: testtypes.ListTypeWithValidateAttributeError{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(s), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "nullWithValidateWarning": { + typ: testtypes.ListTypeWithValidateWarning{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(s), + expected: types.ListNull(types.StringType), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + "nullWithValidateAttributeWarning": { + typ: testtypes.ListTypeWithValidateAttributeWarning{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf(s), + expected: testtypes.ListValueWithValidateAttributeWarning{ + List: types.ListNull(types.StringType), + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + "list": { + typ: types.ListType{ElemType: types.StringType}, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: types.ListValueMust(types.StringType, []attr.Value{ + types.StringValue("a"), + types.StringValue("b"), + types.StringValue("c"), + }), + }, + "listElemWithValidateError": { + typ: types.ListType{ + ElemType: testtypes.StringTypeWithValidateError{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty().AtListIndex(0)), + }, + }, + "listElemWithValidateAttributeError": { + typ: types.ListType{ + ElemType: testtypes.StringTypeWithValidateAttributeError{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty().AtListIndex(0)), + }, + }, + "listElemWithValidateWarning": { + typ: types.ListType{ + ElemType: testtypes.StringTypeWithValidateWarning{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: types.ListValueMust(testtypes.StringTypeWithValidateWarning{}, []attr.Value{ + testtypes.String{ + InternalString: types.StringValue("a"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + testtypes.String{ + InternalString: types.StringValue("b"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + testtypes.String{ + InternalString: types.StringValue("c"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(0)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(1)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(2)), + }, + }, + "listElemWithValidateAttributeWarning": { + typ: types.ListType{ + ElemType: testtypes.StringTypeWithValidateAttributeWarning{ + StringType: testtypes.StringType{}, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: types.ListValueMust(testtypes.StringTypeWithValidateAttributeWarning{}, []attr.Value{ + testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("a"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("b"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("c"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(0)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(1)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(2)), + }, + }, + "tuple": { + typ: types.TupleType{ + ElemTypes: []attr.Type{ + types.StringType, + types.StringType, + types.StringType, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: types.TupleValueMust( + []attr.Type{ + types.StringType, + types.StringType, + types.StringType, + }, + []attr.Value{ + types.StringValue("a"), + types.StringValue("b"), + types.StringValue("c"), + }, + ), + }, + "tupleElemWithValidateError": { + typ: types.TupleType{ + ElemTypes: []attr.Type{ + testtypes.StringTypeWithValidateError{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateError{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateError{ + StringType: testtypes.StringType{}, + }, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty().AtListIndex(0)), + }, + }, + "tupleElemWithValidateAttributeError": { + typ: types.TupleType{ + ElemTypes: []attr.Type{ + testtypes.StringTypeWithValidateAttributeError{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateAttributeError{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateAttributeError{ + StringType: testtypes.StringType{}, + }, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty().AtListIndex(0)), + }, + }, + "tupleElemWithValidateWarning": { + typ: types.TupleType{ + ElemTypes: []attr.Type{ + testtypes.StringTypeWithValidateWarning{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateWarning{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateWarning{ + StringType: testtypes.StringType{}, + }, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: types.TupleValueMust( + []attr.Type{ + testtypes.StringTypeWithValidateWarning{}, + testtypes.StringTypeWithValidateWarning{}, + testtypes.StringTypeWithValidateWarning{}, + }, + []attr.Value{ + testtypes.String{ + InternalString: types.StringValue("a"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + testtypes.String{ + InternalString: types.StringValue("b"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + testtypes.String{ + InternalString: types.StringValue("c"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(0)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(1)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(2)), + }, + }, + "tupleElemWithValidateAttributeWarning": { + typ: types.TupleType{ + ElemTypes: []attr.Type{ + testtypes.StringTypeWithValidateAttributeWarning{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateAttributeWarning{ + StringType: testtypes.StringType{}, + }, + testtypes.StringTypeWithValidateAttributeWarning{ + StringType: testtypes.StringType{}, + }, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: types.TupleValueMust( + []attr.Type{ + testtypes.StringTypeWithValidateAttributeWarning{}, + testtypes.StringTypeWithValidateAttributeWarning{}, + testtypes.StringTypeWithValidateAttributeWarning{}, + }, + []attr.Value{ + testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("a"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("b"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("c"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + }), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(0)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(1)), + testtypes.TestWarningDiagnostic(path.Empty().AtListIndex(2)), + }, + }, + "listWithValidateError": { + typ: testtypes.ListTypeWithValidateError{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "listWithValidateAttributeError": { + typ: testtypes.ListTypeWithValidateAttributeError{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expectedDiags: diag.Diagnostics{ + testtypes.TestErrorDiagnostic(path.Empty()), + }, + }, + "listWithValidateWarning": { + typ: testtypes.ListTypeWithValidateWarning{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: types.ListValueMust( + types.StringType, + []attr.Value{ + types.StringValue("a"), + types.StringValue("b"), + types.StringValue("c"), + }, + ), + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + "listWithValidateAttributeWarning": { + typ: testtypes.ListTypeWithValidateAttributeWarning{ + ListType: types.ListType{ + ElemType: types.StringType, + }, + }, + val: reflect.ValueOf([]string{"a", "b", "c"}), + expected: testtypes.ListValueWithValidateAttributeWarning{ + List: types.ListValueMust( + types.StringType, + []attr.Value{ + types.StringValue("a"), + types.StringValue("b"), + types.StringValue("c"), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + testtypes.TestWarningDiagnostic(path.Empty()), + }, + }, + } + + for name, tc := range testCases { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, diags := refl.FromSlice(context.Background(), tc.typ, tc.val, path.Empty()) + + if diff := cmp.Diff(diags, tc.expectedDiags); diff != "" { + t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) + } + + if diff := cmp.Diff(got, tc.expected); diff != "" { + t.Errorf("unexpected result (+wanted, -got): %s", diff) + } + }) + } +} From ce4b9349e984a5cbbc890feceb492bc50d8864f3 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 2 Apr 2024 15:17:00 +0100 Subject: [PATCH 25/62] Adding switch statements to reflect package FromStruct() function to handle ValidateableAttribute assertions --- internal/reflect/struct.go | 59 ++++- internal/reflect/struct_test.go | 223 ++++++++++++++++++ .../testing/testtypes/objectwithvalidate.go | 38 +++ .../testtypes/objectwithvalidateattribute.go | 85 +++++++ 4 files changed, 395 insertions(+), 10 deletions(-) create mode 100644 internal/testing/testtypes/objectwithvalidate.go create mode 100644 internal/testing/testtypes/objectwithvalidateattribute.go diff --git a/internal/reflect/struct.go b/internal/reflect/struct.go index a4d994e3c..d48ff2d31 100644 --- a/internal/reflect/struct.go +++ b/internal/reflect/struct.go @@ -215,6 +215,9 @@ func FromStruct(ctx context.Context, typ attr.TypeWithAttributeTypes, val reflec path := path.AtName(name) fieldValue := val.Field(fieldNo) + // If the attr implements xattr.ValidateableAttribute, or xattr.TypeWithValidate, + // and the attr does not validate then diagnostics will be added here and returned + // before reaching the switch statement below. attrVal, attrValDiags := FromValue(ctx, attrTypes[name], fieldValue.Interface(), path) diags.Append(attrValDiags...) @@ -227,13 +230,31 @@ func FromStruct(ctx context.Context, typ attr.TypeWithAttributeTypes, val reflec return nil, append(diags, toTerraformValueErrorDiag(err, path)) } - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfObjVal, path)...) + switch t := attrVal.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := attrTypes[name].(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfObjVal, path)...) + + if diags.HasError() { + return nil, diags + } + } } tfObjTyp := tfObjVal.Type() @@ -253,18 +274,36 @@ func FromStruct(ctx context.Context, typ attr.TypeWithAttributeTypes, val reflec AttributeTypes: objTypes, }, objValues) - //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. - if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { - diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) + ret, err := typ.ValueFromTerraform(ctx, tfVal) + if err != nil { + return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + } + + switch t := ret.(type) { + case xattr.ValidateableAttribute: + resp := xattr.ValidateAttributeResponse{} + + t.ValidateAttribute(ctx, + xattr.ValidateAttributeRequest{ + Path: path, + }, + &resp, + ) + + diags.Append(resp.Diagnostics...) if diags.HasError() { return nil, diags } - } + default: + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok { + diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...) - ret, err := typ.ValueFromTerraform(ctx, tfVal) - if err != nil { - return nil, append(diags, valueFromTerraformErrorDiag(err, path)) + if diags.HasError() { + return nil, diags + } + } } return ret, diags diff --git a/internal/reflect/struct_test.go b/internal/reflect/struct_test.go index 87cfbed3c..7d9836a3b 100644 --- a/internal/reflect/struct_test.go +++ b/internal/reflect/struct_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" refl "github.com/hashicorp/terraform-plugin-framework/internal/reflect" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" @@ -992,6 +993,228 @@ func TestFromStruct_errors(t *testing.T) { ), }, }, + "struct-validate-error": { + typ: testtypes.ObjectTypeWithValidateError{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": types.StringType, + }, + }, + }, + val: reflect.ValueOf( + struct { + Test types.String `tfsdk:"test"` + }{}, + ), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Root("test"), + "Error Diagnostic", + "This is an error.", + ), + }, + }, + "struct-validate-attribute-error": { + typ: testtypes.ObjectTypeWithValidateAttributeError{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": types.StringType, + }, + }, + }, + val: reflect.ValueOf( + struct { + Test types.String `tfsdk:"test"` + }{}, + ), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Root("test"), + "Error Diagnostic", + "This is an error.", + ), + }, + }, + "struct-validate-warning": { + typ: testtypes.ObjectTypeWithValidateWarning{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": types.StringType, + }, + }, + }, + val: reflect.ValueOf( + struct { + Test types.String `tfsdk:"test"` + }{ + Test: types.StringValue("test"), + }, + ), + expected: types.ObjectValueMust( + map[string]attr.Type{ + "test": types.StringType, + }, + map[string]attr.Value{ + "test": types.StringValue("test"), + }, + ), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeWarningDiagnostic( + path.Root("test"), + "Warning Diagnostic", + "This is a warning.", + ), + }, + }, + "struct-validate-attribute-warning": { + typ: testtypes.ObjectTypeWithValidateAttributeWarning{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": types.StringType, + }, + }, + }, + val: reflect.ValueOf( + struct { + Test types.String `tfsdk:"test"` + }{ + Test: types.StringValue("test"), + }, + ), + expected: testtypes.ObjectValueWithValidateAttributeWarning{ + Object: types.ObjectValueMust( + map[string]attr.Type{ + "test": types.StringType, + }, + map[string]attr.Value{ + "test": types.StringValue("test"), + }, + ), + }, + expectedDiags: diag.Diagnostics{ + diag.NewAttributeWarningDiagnostic( + path.Root("test"), + "Warning Diagnostic", + "This is a warning.", + ), + }, + }, + "struct-field-validate-error": { + typ: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": testtypes.StringTypeWithValidateError{}, + }, + }, + val: reflect.ValueOf( + struct { + Test types.String `tfsdk:"test"` + }{}, + ), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Root("test").AtName("test"), + "Error Diagnostic", + "This is an error.", + ), + }, + }, + "struct-field-validate-attribute-error": { + typ: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + val: reflect.ValueOf( + struct { + Test testtypes.StringValueWithValidateAttributeError `tfsdk:"test"` + }{ + Test: testtypes.StringValueWithValidateAttributeError{ + InternalString: testtypes.String{ + InternalString: types.String{}, + CreatedBy: testtypes.StringTypeWithValidateAttributeError{}, + }, + }, + }, + ), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Root("test").AtName("test"), + "Error Diagnostic", + "This is an error.", + ), + }, + }, + "struct-field-validate-warning": { + typ: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": testtypes.StringTypeWithValidateWarning{}, + }, + }, + val: reflect.ValueOf( + struct { + Test types.String `tfsdk:"test"` + }{ + Test: types.StringValue("test"), + }, + ), + expected: types.ObjectValueMust( + map[string]attr.Type{ + "test": testtypes.StringTypeWithValidateWarning{}, + }, + map[string]attr.Value{ + "test": testtypes.String{ + InternalString: types.StringValue("test"), + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + }, + }, + ), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeWarningDiagnostic( + path.Root("test").AtName("test"), + "Warning Diagnostic", + "This is a warning.", + ), + }, + }, + "struct-field-validate-attribute-warning": { + typ: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "test": testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + val: reflect.ValueOf( + struct { + Test testtypes.StringValueWithValidateAttributeWarning `tfsdk:"test"` + }{ + Test: testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("test"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + }, + ), + expected: types.ObjectValueMust( + map[string]attr.Type{ + "test": testtypes.StringTypeWithValidateAttributeWarning{}, + }, + map[string]attr.Value{ + "test": testtypes.StringValueWithValidateAttributeWarning{ + InternalString: testtypes.String{ + InternalString: types.StringValue("test"), + CreatedBy: testtypes.StringTypeWithValidateAttributeWarning{}, + }, + }, + }, + ), + expectedDiags: diag.Diagnostics{ + diag.NewAttributeWarningDiagnostic( + path.Root("test").AtName("test"), + "Warning Diagnostic", + "This is a warning.", + ), + }, + }, "struct-has-untagged-fields": { typ: types.ObjectType{ AttrTypes: map[string]attr.Type{ diff --git a/internal/testing/testtypes/objectwithvalidate.go b/internal/testing/testtypes/objectwithvalidate.go new file mode 100644 index 000000000..5766d8879 --- /dev/null +++ b/internal/testing/testtypes/objectwithvalidate.go @@ -0,0 +1,38 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var ( + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + _ xattr.TypeWithValidate = ObjectTypeWithValidateError{} + //nolint:staticcheck // xattr.TypeWithValidate is deprecated, but we still need to support it. + _ xattr.TypeWithValidate = ObjectTypeWithValidateWarning{} +) + +type ObjectTypeWithValidateError struct { + types.ObjectType +} + +type ObjectTypeWithValidateWarning struct { + types.ObjectType +} + +func (t ObjectTypeWithValidateError) Validate(ctx context.Context, in tftypes.Value, path path.Path) diag.Diagnostics { + return diag.Diagnostics{TestErrorDiagnostic(path)} +} + +func (t ObjectTypeWithValidateWarning) Validate(ctx context.Context, in tftypes.Value, path path.Path) diag.Diagnostics { + return diag.Diagnostics{TestWarningDiagnostic(path)} +} diff --git a/internal/testing/testtypes/objectwithvalidateattribute.go b/internal/testing/testtypes/objectwithvalidateattribute.go new file mode 100644 index 000000000..438a24278 --- /dev/null +++ b/internal/testing/testtypes/objectwithvalidateattribute.go @@ -0,0 +1,85 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/attr/xattr" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ObjectTypeWithValidateAttributeError struct { + types.ObjectType +} + +func (t ObjectTypeWithValidateAttributeError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.ObjectType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + list, ok := val.(types.Object) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.Object", val) + } + + return ObjectValueWithValidateAttributeError{ + list, + }, nil +} + +var _ xattr.ValidateableAttribute = ObjectValueWithValidateAttributeError{} + +type ObjectValueWithValidateAttributeError struct { + types.Object +} + +func (v ObjectValueWithValidateAttributeError) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestErrorDiagnostic(req.Path)) +} + +type ObjectTypeWithValidateAttributeWarning struct { + types.ObjectType +} + +func (t ObjectTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.ObjectType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + list, ok := val.(types.Object) + if !ok { + return nil, fmt.Errorf("cannot assert %T as types.Object", val) + } + + return ObjectValueWithValidateAttributeWarning{ + list, + }, nil +} + +var _ xattr.ValidateableAttribute = ObjectValueWithValidateAttributeWarning{} + +type ObjectValueWithValidateAttributeWarning struct { + types.Object +} + +func (v ObjectValueWithValidateAttributeWarning) Equal(o attr.Value) bool { + other, ok := o.(ObjectValueWithValidateAttributeWarning) + + if !ok { + return false + } + + return v.Object.Equal(other.Object) +} + +func (v ObjectValueWithValidateAttributeWarning) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + resp.Diagnostics.Append(TestWarningDiagnostic(req.Path)) +} From 7df68724036a7941c8aaf225c0867215d79d7605 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Tue, 2 Apr 2024 13:00:25 -0400 Subject: [PATCH 26/62] Switch dynamic parameter test to use `DynamicTypeMust()` --- internal/fromproto5/arguments_data_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index dcf2dad96..377f097ed 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -553,7 +553,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, "dynamic-parameter-Validators": { input: []*tfprotov5.DynamicValue{ - createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), }, definition: function.Definition{ Parameters: []function.Parameter{ @@ -1661,6 +1661,8 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), ), }, + + //TODO: Add test cases for variadic parameter } for name, testCase := range testCases { From d04737cff89ceb568167d4e445406615f6897635 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 3 Apr 2024 10:30:49 +0100 Subject: [PATCH 27/62] fromproto5+fromproto6: Add further test coverage for validation of function parameters in ArgumentsData() function --- internal/fromproto5/arguments_data.go | 14 +- internal/fromproto5/arguments_data_test.go | 287 +++++++++++++++++- internal/fromproto6/arguments_data.go | 14 +- internal/fromproto6/arguments_data_test.go | 287 +++++++++++++++++- .../testtypes/stringwithvalidateparameter.go | 85 ++++++ 5 files changed, 667 insertions(+), 20 deletions(-) create mode 100644 internal/testing/testtypes/stringwithvalidateparameter.go diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 4edca1a86..b1a9dbaa1 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -110,7 +110,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def // This is intentionally below the conversion of tftypes.Value to attr.Value // so it can be updated for any new type system validation interfaces. Note that the - // original xattr.TypeWithValidation interface must set a path.Path, + // original xattr.TypeWithValidate interface must set a path.Path, // which will always be incorrect in the context of functions. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 @@ -148,14 +148,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def logging.FrameworkTrace(ctx, "Called provider defined Type Validate") - if diags.HasError() { - funcErrFromDiags := function.FuncErrorFromDiags(ctx, diags) + funcErrFromDiags := function.FuncErrorFromDiags(ctx, diags) - if funcErrFromDiags != nil { - funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( - pos, - funcErrFromDiags.Error())) - } + if funcErrFromDiags != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + funcErrFromDiags.Error())) continue } diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index b23d231d9..a760bdeed 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -4,12 +4,14 @@ package fromproto5_test import ( + "bytes" "context" "testing" "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-log/tflogtest" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" @@ -26,6 +28,7 @@ func TestArgumentsData(t *testing.T) { definition function.Definition expected function.ArgumentsData expectedFuncError *function.FuncError + expectedLog []map[string]interface{} }{ "nil": { input: nil, @@ -179,7 +182,15 @@ func TestArgumentsData(t *testing.T) { Bool: basetypes.NewBoolValue(true), }, }), - // Function error is not generated as diagnostic raised is warning. + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, }, "parameters-one-variadicparameter-zero": { input: []*tfprotov5.DynamicValue{ @@ -264,6 +275,125 @@ func TestArgumentsData(t *testing.T) { basetypes.NewBoolValue(false), }), }, + "parameters-multiple-TypeWithValidation-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateError{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 1, + "Error Diagnostic: This is an error.", + ), + }, + "parameters-multiple-TypeWithParameterValidation-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateParameterError{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 1, + "This is a function error", + ), + }, + "parameters-multiple-TypeWithValidation-warning": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateWarning{}, + }, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateWarning{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Bool{ + Bool: basetypes.NewBoolValue(true), + CreatedBy: testtypes.BoolTypeWithValidateWarning{}, + }, + testtypes.Bool{ + Bool: basetypes.NewBoolValue(false), + CreatedBy: testtypes.BoolTypeWithValidateWarning{}, + }, + }), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, + "parameters-multiple-TypeWithValidation-warning-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateWarning{}, + }, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateError{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Bool{ + Bool: basetypes.NewBoolValue(true), + CreatedBy: testtypes.BoolTypeWithValidateWarning{}, + }, + }), + expectedFuncError: function.NewArgumentFuncError( + 1, + "Error Diagnostic: This is an error.", + ), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, "parameters-multiple-variadicparameter-zero": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), @@ -393,6 +523,68 @@ func TestArgumentsData(t *testing.T) { ), }), }, + "variadicparameter-one-TypeWithValidation-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: This is an error.", + ), + }, + "variadicparameter-one-TypeWithParameterValidation-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateParameterError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "This is a function error", + ), + }, + "variadicparameter-one-TypeWithValidation-warning": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateWarning{}, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + testtypes.StringTypeWithValidateWarning{}, + }, + []attr.Value{ + testtypes.String{ + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + InternalString: basetypes.NewStringValue("varg-arg0"), + }, + }, + ), + }), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, "variadicparameter-multiple": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), @@ -414,6 +606,83 @@ func TestArgumentsData(t *testing.T) { ), }), }, + "variadicparameter-multiple-TypeWithValidation-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg1")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: This is an error.", + ), + }, + "variadicparameter-multiple-TypeWithParameterValidation-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg1")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateParameterError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "This is a function error", + ), + }, + "variadicparameter-multiple-TypeWithValidation-warning": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg1")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateWarning{}, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + testtypes.StringTypeWithValidateWarning{}, + testtypes.StringTypeWithValidateWarning{}, + }, + []attr.Value{ + testtypes.String{ + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + InternalString: basetypes.NewStringValue("varg-arg0"), + }, + testtypes.String{ + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + InternalString: basetypes.NewStringValue("varg-arg1"), + }, + }, + ), + }), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, } for name, testCase := range testCases { @@ -422,7 +691,17 @@ func TestArgumentsData(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.ArgumentsData(context.Background(), testCase.input, testCase.definition) + var output bytes.Buffer + + ctx := tflogtest.RootLogger(context.Background(), &output) + + got, diags := fromproto5.ArgumentsData(ctx, testCase.input, testCase.definition) + + entries, err := tflogtest.MultilineJSONDecode(&output) + + if err != nil { + t.Fatalf("unable to read multiple line JSON: %s", err) + } if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -431,6 +710,10 @@ func TestArgumentsData(t *testing.T) { if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { t.Errorf("unexpected diagnostics difference: %s", diff) } + + if diff := cmp.Diff(entries, testCase.expectedLog); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } }) } } diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 58fb6e492..dd163c1a5 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -110,7 +110,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def // This is intentionally below the conversion of tftypes.Value to attr.Value // so it can be updated for any new type system validation interfaces. Note that the - // original xattr.TypeWithValidation interface must set a path.Path, + // original xattr.TypeWithValidate interface must set a path.Path, // which will always be incorrect in the context of functions. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 @@ -148,14 +148,12 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def logging.FrameworkTrace(ctx, "Called provider defined Type Validate") - if diags.HasError() { - funcErrFromDiags := function.FuncErrorFromDiags(ctx, diags) + funcErrFromDiags := function.FuncErrorFromDiags(ctx, diags) - if funcErrFromDiags != nil { - funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( - pos, - funcErrFromDiags.Error())) - } + if funcErrFromDiags != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + funcErrFromDiags.Error())) continue } diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index fcca1de63..c0bdc6cf3 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -4,12 +4,14 @@ package fromproto6_test import ( + "bytes" "context" "testing" "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-log/tflogtest" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" @@ -26,6 +28,7 @@ func TestArgumentsData(t *testing.T) { definition function.Definition expected function.ArgumentsData expectedFuncError *function.FuncError + expectedLog []map[string]interface{} }{ "nil": { input: nil, @@ -179,7 +182,15 @@ func TestArgumentsData(t *testing.T) { Bool: basetypes.NewBoolValue(true), }, }), - // Function error is not generated as diagnostic raised is warning. + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, }, "parameters-one-variadicparameter-zero": { input: []*tfprotov6.DynamicValue{ @@ -264,6 +275,125 @@ func TestArgumentsData(t *testing.T) { basetypes.NewBoolValue(false), }), }, + "parameters-multiple-TypeWithValidation-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateError{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 1, + "Error Diagnostic: This is an error.", + ), + }, + "parameters-multiple-TypeWithParameterValidation-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateParameterError{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 1, + "This is a function error", + ), + }, + "parameters-multiple-TypeWithValidation-warning": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateWarning{}, + }, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateWarning{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Bool{ + Bool: basetypes.NewBoolValue(true), + CreatedBy: testtypes.BoolTypeWithValidateWarning{}, + }, + testtypes.Bool{ + Bool: basetypes.NewBoolValue(false), + CreatedBy: testtypes.BoolTypeWithValidateWarning{}, + }, + }), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, + "parameters-multiple-TypeWithValidation-warning-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.Bool, false)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateWarning{}, + }, + function.BoolParameter{ + CustomType: testtypes.BoolTypeWithValidateError{}, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Bool{ + Bool: basetypes.NewBoolValue(true), + CreatedBy: testtypes.BoolTypeWithValidateWarning{}, + }, + }), + expectedFuncError: function.NewArgumentFuncError( + 1, + "Error Diagnostic: This is an error.", + ), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, "parameters-multiple-variadicparameter-zero": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), @@ -393,6 +523,68 @@ func TestArgumentsData(t *testing.T) { ), }), }, + "variadicparameter-one-TypeWithValidation-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: This is an error.", + ), + }, + "variadicparameter-one-TypeWithParameterValidation-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateParameterError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "This is a function error", + ), + }, + "variadicparameter-one-TypeWithValidation-warning": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateWarning{}, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + testtypes.StringTypeWithValidateWarning{}, + }, + []attr.Value{ + testtypes.String{ + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + InternalString: basetypes.NewStringValue("varg-arg0"), + }, + }, + ), + }), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, "variadicparameter-multiple": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), @@ -414,6 +606,83 @@ func TestArgumentsData(t *testing.T) { ), }), }, + "variadicparameter-multiple-TypeWithValidation-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg1")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: This is an error.", + ), + }, + "variadicparameter-multiple-TypeWithParameterValidation-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg1")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateParameterError{}, + }, + }, + expected: function.NewArgumentsData(nil), + expectedFuncError: function.NewArgumentFuncError( + 0, + "This is a function error", + ), + }, + "variadicparameter-multiple-TypeWithValidation-warning": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg0")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "varg-arg1")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + CustomType: testtypes.StringTypeWithValidateWarning{}, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + testtypes.StringTypeWithValidateWarning{}, + testtypes.StringTypeWithValidateWarning{}, + }, + []attr.Value{ + testtypes.String{ + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + InternalString: basetypes.NewStringValue("varg-arg0"), + }, + testtypes.String{ + CreatedBy: testtypes.StringTypeWithValidateWarning{}, + InternalString: basetypes.NewStringValue("varg-arg1"), + }, + }, + ), + }), + expectedLog: []map[string]interface{}{ + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + { + "@level": "warn", + "@message": "warning: call function", + "@module": "provider", + "detail": "This is a warning.", + "summary": "Warning Diagnostic", + }, + }, + }, } for name, testCase := range testCases { @@ -422,7 +691,17 @@ func TestArgumentsData(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.ArgumentsData(context.Background(), testCase.input, testCase.definition) + var output bytes.Buffer + + ctx := tflogtest.RootLogger(context.Background(), &output) + + got, diags := fromproto6.ArgumentsData(ctx, testCase.input, testCase.definition) + + entries, err := tflogtest.MultilineJSONDecode(&output) + + if err != nil { + t.Fatalf("unable to read multiple line JSON: %s", err) + } if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) @@ -431,6 +710,10 @@ func TestArgumentsData(t *testing.T) { if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { t.Errorf("unexpected diagnostics difference: %s", diff) } + + if diff := cmp.Diff(entries, testCase.expectedLog); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } }) } } diff --git a/internal/testing/testtypes/stringwithvalidateparameter.go b/internal/testing/testtypes/stringwithvalidateparameter.go new file mode 100644 index 000000000..8d6beec42 --- /dev/null +++ b/internal/testing/testtypes/stringwithvalidateparameter.go @@ -0,0 +1,85 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package testtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/types/validation" +) + +type StringTypeWithValidateParameterError struct { + StringType +} + +func (t StringTypeWithValidateParameterError) Equal(o attr.Type) bool { + other, ok := o.(StringTypeWithValidateParameterError) + if !ok { + return false + } + return t == other +} + +func (t StringTypeWithValidateParameterError) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + val, err := t.StringType.ValueFromTerraform(ctx, in) + if err != nil { + return nil, err + } + + newString, ok := val.(String) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", val) + } + + newString.CreatedBy = t + + return StringValueWithValidateParameterError{ + InternalString: newString, + }, nil +} + +var _ validation.ValidateableParameter = StringValueWithValidateParameterError{} + +type StringValueWithValidateParameterError struct { + InternalString String +} + +func (v StringValueWithValidateParameterError) Type(ctx context.Context) attr.Type { + return v.InternalString.Type(ctx) +} + +func (v StringValueWithValidateParameterError) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + return v.InternalString.ToTerraformValue(ctx) +} + +func (v StringValueWithValidateParameterError) Equal(value attr.Value) bool { + other, ok := value.(StringValueWithValidateParameterError) + + if !ok { + return false + } + + return v == other +} + +func (v StringValueWithValidateParameterError) IsNull() bool { + return v.InternalString.IsNull() +} + +func (v StringValueWithValidateParameterError) IsUnknown() bool { + return v.InternalString.IsUnknown() +} + +func (v StringValueWithValidateParameterError) String() string { + return v.InternalString.String() +} + +func (v StringValueWithValidateParameterError) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { + resp.Error = function.NewArgumentFuncError(req.Position, "This is a function error") +} From b6d8b93eb7c7d469dee7b5fe89371f49914e640d Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 3 Apr 2024 11:51:18 +0100 Subject: [PATCH 28/62] xfwfunction: Moving Definition.Parameter() method from function package to xfwfunction package Parameter() function * xfwfunction package is purely to avoid import cycles --- internal/fromproto5/arguments_data.go | 9 +- internal/fromproto5/arguments_data_test.go | 4 +- internal/fromproto6/arguments_data.go | 9 +- internal/fromproto6/arguments_data_test.go | 4 +- internal/fwfunction/xfwfunction/doc.go | 6 + internal/fwfunction/xfwfunction/parameter.go | 46 ++++++ .../fwfunction/xfwfunction/parameter_test.go | 145 ++++++++++++++++++ 7 files changed, 209 insertions(+), 14 deletions(-) create mode 100644 internal/fwfunction/xfwfunction/doc.go create mode 100644 internal/fwfunction/xfwfunction/parameter.go create mode 100644 internal/fwfunction/xfwfunction/parameter_test.go diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index b1a9dbaa1..44e60771b 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -54,12 +55,10 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def var funcError *function.FuncError for position, argument := range arguments { - parameter, parameterDiags := definition.Parameter(ctx, position) + parameter, parameterFuncError := xfwfunction.Parameter(ctx, definition, position) - funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) - - if funcError != nil { - return function.NewArgumentsData(nil), funcError + if parameterFuncError != nil { + return function.NewArgumentsData(nil), function.ConcatFuncErrors(funcError, parameterFuncError) } parameterType := parameter.GetType() diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index a760bdeed..86b9349a4 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -619,7 +619,7 @@ func TestArgumentsData(t *testing.T) { expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, - "Error Diagnostic: This is an error.", + "Error Diagnostic: This is an error.\nError Diagnostic: This is an error.", ), }, "variadicparameter-multiple-TypeWithParameterValidation-error": { @@ -635,7 +635,7 @@ func TestArgumentsData(t *testing.T) { expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, - "This is a function error", + "This is a function error\nThis is a function error", ), }, "variadicparameter-multiple-TypeWithValidation-warning": { diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index dd163c1a5..7d734ee09 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -54,12 +55,10 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def var funcError *function.FuncError for position, argument := range arguments { - parameter, parameterDiags := definition.Parameter(ctx, position) + parameter, parameterFuncError := xfwfunction.Parameter(ctx, definition, position) - funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) - - if funcError != nil { - return function.NewArgumentsData(nil), funcError + if parameterFuncError != nil { + return function.NewArgumentsData(nil), function.ConcatFuncErrors(funcError, parameterFuncError) } parameterType := parameter.GetType() diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index c0bdc6cf3..aa49743e8 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -619,7 +619,7 @@ func TestArgumentsData(t *testing.T) { expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, - "Error Diagnostic: This is an error.", + "Error Diagnostic: This is an error.\nError Diagnostic: This is an error.", ), }, "variadicparameter-multiple-TypeWithParameterValidation-error": { @@ -635,7 +635,7 @@ func TestArgumentsData(t *testing.T) { expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, - "This is a function error", + "This is a function error\nThis is a function error", ), }, "variadicparameter-multiple-TypeWithValidation-warning": { diff --git a/internal/fwfunction/xfwfunction/doc.go b/internal/fwfunction/xfwfunction/doc.go new file mode 100644 index 000000000..18baa8635 --- /dev/null +++ b/internal/fwfunction/xfwfunction/doc.go @@ -0,0 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Package xfwfunction contains additional functions for use with provider defined functions. +// This package is separate from the fwfunction package to prevent import cycles. +package xfwfunction diff --git a/internal/fwfunction/xfwfunction/parameter.go b/internal/fwfunction/xfwfunction/parameter.go new file mode 100644 index 000000000..35377650b --- /dev/null +++ b/internal/fwfunction/xfwfunction/parameter.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package xfwfunction + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/function" +) + +// Parameter returns the Parameter for a given argument position. This may be +// from the Parameters field or, if defined, the VariadicParameter field. An +// error diagnostic is raised if the position is outside the expected arguments. +func Parameter(ctx context.Context, d function.Definition, position int) (function.Parameter, *function.FuncError) { + if d.VariadicParameter != nil && position >= len(d.Parameters) { + return d.VariadicParameter, nil + } + + pos := int64(position) + + if len(d.Parameters) == 0 { + return nil, function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + "Function does not implement parameters.\n"+ + fmt.Sprintf("Given position: %d", position), + ) + } + + if position >= len(d.Parameters) { + return nil, function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Max argument position: %d\n", len(d.Parameters)-1)+ + fmt.Sprintf("Given position: %d", position), + ) + } + + return d.Parameters[position], nil +} diff --git a/internal/fwfunction/xfwfunction/parameter_test.go b/internal/fwfunction/xfwfunction/parameter_test.go new file mode 100644 index 000000000..ad96d2783 --- /dev/null +++ b/internal/fwfunction/xfwfunction/parameter_test.go @@ -0,0 +1,145 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package xfwfunction_test + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-framework/function" + "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" +) + +func TestParameter(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + definition function.Definition + position int + expected function.Parameter + expectedFuncError *function.FuncError + }{ + "none": { + definition: function.Definition{ + // no Parameters or VariadicParameter + }, + position: 0, + expected: nil, + expectedFuncError: function.NewArgumentFuncError( + int64(0), + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + "Function does not implement parameters.\n"+ + "Given position: 0", + ), + }, + "parameters-first": { + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + function.Int64Parameter{}, + function.StringParameter{}, + }, + }, + position: 0, + expected: function.BoolParameter{}, + }, + "parameters-last": { + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + function.Int64Parameter{}, + function.StringParameter{}, + }, + }, + position: 2, + expected: function.StringParameter{}, + }, + "parameters-middle": { + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + function.Int64Parameter{}, + function.StringParameter{}, + }, + }, + position: 1, + expected: function.Int64Parameter{}, + }, + "parameters-only": { + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + }, + }, + position: 0, + expected: function.BoolParameter{}, + }, + "parameters-over": { + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + }, + }, + position: 1, + expected: nil, + expectedFuncError: function.NewArgumentFuncError( + int64(1), + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + "Max argument position: 0\n"+ + "Given position: 1", + ), + }, + "variadicparameter-and-parameters-select-parameter": { + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + }, + VariadicParameter: function.StringParameter{}, + }, + position: 0, + expected: function.BoolParameter{}, + }, + "variadicparameter-and-parameters-select-variadicparameter": { + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{}, + }, + VariadicParameter: function.StringParameter{}, + }, + position: 1, + expected: function.StringParameter{}, + }, + "variadicparameter-only": { + definition: function.Definition{ + VariadicParameter: function.StringParameter{}, + }, + position: 0, + expected: function.StringParameter{}, + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, funcError := xfwfunction.Parameter(context.Background(), testCase.definition, testCase.position) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + + if diff := cmp.Diff(funcError, testCase.expectedFuncError); diff != "" { + t.Errorf("unexpected diagnostics difference: %s", diff) + } + }) + } +} From 3e0bc53882c701acb4f2b7118fa896258891e183 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 3 Apr 2024 12:00:58 +0100 Subject: [PATCH 29/62] fromproto5+fromproto6: Fix function error message in ArgumentsData() --- internal/fromproto5/arguments_data.go | 2 +- internal/fromproto6/arguments_data.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 44e60771b..959a1a797 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -101,7 +101,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "Unable to Convert Function Argument"+ "An unexpected error was encountered when converting the function argument from the protocol type. "+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %stringVal", position, err), + fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %s", position, err), )) return function.NewArgumentsData(nil), funcError diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 7d734ee09..267ce7eb5 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -101,7 +101,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "Unable to Convert Function Argument"+ "An unexpected error was encountered when converting the function argument from the protocol type. "+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %stringVal", position, err), + fmt.Sprintf("Unable to convert tftypes to framework type at position %d: %s", position, err), )) return function.NewArgumentsData(nil), funcError From c8fd89800736235e6b43a425a220bab3bab0c277 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Wed, 3 Apr 2024 20:54:58 -0400 Subject: [PATCH 30/62] Correct error handling and dynamic type test cases --- internal/fromproto5/arguments_data.go | 10 ++++------ internal/fromproto5/arguments_data_test.go | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 4ee8fd90a..cc5d85558 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -57,12 +57,10 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def for position, argument := range arguments { parameter, parameterDiags := definition.Parameter(ctx, position) - funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) - - //TODO: ask about the error handling here - //if funcError != nil { - // return function.NewArgumentsData(nil), funcError - //} + if parameterDiags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) + return function.NewArgumentsData(nil), funcError + } parameterType := parameter.GetType() diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 377f097ed..0a4038618 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -553,7 +553,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, "dynamic-parameter-Validators": { input: []*tfprotov5.DynamicValue{ - DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), }, definition: function.Definition{ Parameters: []function.Parameter{ From 6de03825ab0620c284816ef90a5f1cbff5a27ef6 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Apr 2024 14:43:32 +0100 Subject: [PATCH 31/62] website: Add documentation for usage of xattr.ValidateableAttribute and validation.ValidateableParameter --- .../framework/functions/parameters/index.mdx | 4 + .../framework/handling-data/types/custom.mdx | 72 ++++++++++++++- website/docs/plugin/framework/validation.mdx | 91 +++++++++++++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) diff --git a/website/docs/plugin/framework/functions/parameters/index.mdx b/website/docs/plugin/framework/functions/parameters/index.mdx index e0f23042c..2b2b6538c 100644 --- a/website/docs/plugin/framework/functions/parameters/index.mdx +++ b/website/docs/plugin/framework/functions/parameters/index.mdx @@ -94,3 +94,7 @@ Parameter names are used in runtime errors to highlight which parameter is causi │ │ Invalid value for "bool_param" parameter: a bool is required. ``` + +## Parameter Validation + +Parameter validation handling is enabled by using a custom value type which implements the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter). Refer to [Custom Types](/terraform/plugin/framework/handling-data/types/custom) for further details on creating provider-defined types and values \ No newline at end of file diff --git a/website/docs/plugin/framework/handling-data/types/custom.mdx b/website/docs/plugin/framework/handling-data/types/custom.mdx index 7a7b8e879..f0840949d 100644 --- a/website/docs/plugin/framework/handling-data/types/custom.mdx +++ b/website/docs/plugin/framework/handling-data/types/custom.mdx @@ -308,7 +308,77 @@ func (v CustomStringValue) StringSemanticEquals(ctx context.Context, newValuable ### Validation -Validation handling enables the schema type to automatically raise warning and/or error diagnostics when a value is determined to be invalid. This handling simplifies schema definitions by removing the need for each attribute to repetitively define validators. This schema type functionality is automatically checked by the framework any time a value is created. +#### Value Validation + +Validation handling in custom value types can be enabled for schema attribute values, or provider-defined function parameters. + +Implement the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) on the custom value type to define and enable validation handling for a schema attribute, which will automatically raise warning and/or error diagnostics when a value is determined to be invalid. + +Immplement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. + +If the custom value type is to be used for both schema attribute values and provider-defined function parameters, implement both interfaces. + +```go +// Implementation of the xattr.ValidateableAttribute interface +func (v CustomStringValue) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + if v.IsNull() || v.IsUnknown() { + return + } + + err := v.validate(v.ValueString()) + + if err != nil { + resp.Diagnostics.AddAttributeError( + req.Path, + "Invalid RFC 3339 String Value", + "An unexpected error occurred while converting a string value that was expected to be RFC 3339 format. "+ + "The RFC 3339 string format is YYYY-MM-DDTHH:MM:SSZ, such as 2006-01-02T15:04:05Z or 2006-01-02T15:04:05+07:00.\n\n"+ + "Path: "+req.Path.String()+"\n"+ + "Given Value: "+v.ValueString()+"\n"+ + "Error: "+err.Error(), + ) + + return + } +} + +// Implementation of the validation.ValidateableParameter interface +func (v CustomStringValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { + if v.IsNull() || v.IsUnknown() { + return + } + + err := v.validate(v.ValueString()) + + if err != nil { + resp.Error = function.NewArgumentFuncError( + req.Position, + "Invalid RFC 3339 String Value: "+ + "An unexpected error occurred while converting a string value that was expected to be RFC 3339 format. "+ + "The RFC 3339 string format is YYYY-MM-DDTHH:MM:SSZ, such as 2006-01-02T15:04:05Z or 2006-01-02T15:04:05+07:00.\n\n"+ + fmt.Sprintf("Position: %d", req.Position)+"\n"+ + "Given Value: "+v.ValueString()+"\n"+ + "Error: "+err.Error(), + ) + } +} + +func (v CustomStringValue) validate(in string) error { + _, err := time.Parse(time.RFC3339, in) + + return err +} +``` + +#### Type Validation + + + +`Value` validation should be used in preference to `Type` validation. Refer to [Value Validation](#value-validation) for more information. + +The [`xattr.TypeWithValidate` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate) has been deprecated. Use the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute), and [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) instead. + + Implement the [`xattr.TypeWithValidate`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate) interface on the value type to define and enable this behavior. diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index f55469f88..c210ffe60 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -225,8 +225,93 @@ func Int64IsGreaterThan(expressions ...path.Expression) validator.Int64 { } ``` +## Value Validation + +Validation of custom value types can be used for both attribute values and provider-defined function parameter values. This can be useful if you have consistent validation rules for a specific value type across multiple attributes or function parameters. + +When you implement validation on a custom value type associated with a schema attribute, you do not need to declare the same validation on the attribute, but you can supply additional validations in that manner. For example: + +```go +// Typically within the schema.Schema returned by Schema() for a provider, +// resource, or data source. +schema.StringAttribute{ + // ... other Attribute configuration ... + + // This is an example type with a corresponding custom value type + // which implements its own validation + CustomType: computeInstanceIdentifierType, + + // This is optional, example validation that is checked in addition + // to any validation performed by the custom value type + Validators: []validator.String{ + stringvalidator.LengthBetween(10, 256), + }, +} +``` + +### Defining Value Validation + +To support validation for a custom value type, you must implement [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) for attribute validation, or [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) for provider-defined function parameter validation. Both interfaces can be implemented if the same custom type is used for both attributes and function parameters. + +For example: + +```go +// Ensure the implementation satisfies the expected interfaces +var _ basetypes.StringValuable = computeInstanceIdentifierType{} +var _ xattr.ValidateableAttribute = computeInstanceIdentifierType{} +var _ validation.ValidateableParameter = computeInstanceIdentifierType{} + +// Other methods to implement the attr.Value interface are omitted for brevity +type computeInstanceIdentifierValue struct { + basetypes.StringValue +} + +// Implementation of the xattr.ValidateableAttribute interface +func (v computeInstanceIdentifierValue) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { + if v.IsNull() || v.IsUnknown() { + return + } + + if !v.isValid(v.ValueString()) { + resp.Diagnostics.AddAttributeError( + req.Path, + "Compute Instance Type Validation Error", + fmt.Sprintf("Missing `instance-` prefix, got: %s", v.ValueString()), + ) + + return + } +} + +// Implementation of the validation.ValidateableParameter interface +func (v computeInstanceIdentifierValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { + if v.IsNull() || v.IsUnknown() { + return + } + + if !v.isValid(v.ValueString()) { + resp.Error = function.NewArgumentFuncError( + req.Position, + fmt.Sprintf("Compute Instance Type Validation Error: Missing `instance-` prefix, got: %s", v.ValueString()), + ) + + return + } +} + +func (v computeInstanceIdentifierValue) isValid(in string) bool { + return strings.HasPrefix(in, "instance-") +} +``` + ## Type Validation + + +`Value` validation should be used in preference to `Type` validation. Refer to [Value Validation](#value-validation) for more information. + + + You may want to create a custom type to simplify schemas if your provider contains common attribute values with consistent validation rules. When you implement validation on a type, you do not need to declare the same validation on the attribute, but you can supply additional validations in that manner. For example: ```go @@ -248,6 +333,12 @@ schema.StringAttribute{ ### Defining Type Validation + + +The [`xattr.TypeWithValidate` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate) has been deprecated. Refer to [Defining Value Validation](#defining-value-validation) for more information about using [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute), and [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) instead. + + + To support validation within a type, you must implement the [`xattr.TypeWithValidate` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate). For example: ```go From ebea449c05ba129bef62c3c04dd812d4ed0ad7d7 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Apr 2024 15:38:22 +0100 Subject: [PATCH 32/62] website: Add documentation for usage of xattr.ValidateableAttribute and validation.ValidateableParameter --- .../framework/handling-data/types/custom.mdx | 78 ++++++++++--------- website/docs/plugin/framework/validation.mdx | 11 +-- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/website/docs/plugin/framework/handling-data/types/custom.mdx b/website/docs/plugin/framework/handling-data/types/custom.mdx index f0840949d..99eab103f 100644 --- a/website/docs/plugin/framework/handling-data/types/custom.mdx +++ b/website/docs/plugin/framework/handling-data/types/custom.mdx @@ -316,57 +316,59 @@ Implement the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/githu Immplement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. +Value type-specific interfaces are also provided as a convenience, for example [`validation.StringValuableWithValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableAttribute), and [`validation.StringValuableWithValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableParameter). + If the custom value type is to be used for both schema attribute values and provider-defined function parameters, implement both interfaces. ```go // Implementation of the xattr.ValidateableAttribute interface func (v CustomStringValue) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { - if v.IsNull() || v.IsUnknown() { - return - } - - err := v.validate(v.ValueString()) - - if err != nil { - resp.Diagnostics.AddAttributeError( - req.Path, - "Invalid RFC 3339 String Value", - "An unexpected error occurred while converting a string value that was expected to be RFC 3339 format. "+ - "The RFC 3339 string format is YYYY-MM-DDTHH:MM:SSZ, such as 2006-01-02T15:04:05Z or 2006-01-02T15:04:05+07:00.\n\n"+ - "Path: "+req.Path.String()+"\n"+ - "Given Value: "+v.ValueString()+"\n"+ - "Error: "+err.Error(), - ) - - return - } + if v.IsNull() || v.IsUnknown() { + return + } + + err := v.validate(v.ValueString()) + + if err != nil { + resp.Diagnostics.AddAttributeError( + req.Path, + "Invalid RFC 3339 String Value", + "An unexpected error occurred while converting a string value that was expected to be RFC 3339 format. "+ + "The RFC 3339 string format is YYYY-MM-DDTHH:MM:SSZ, such as 2006-01-02T15:04:05Z or 2006-01-02T15:04:05+07:00.\n\n"+ + "Path: "+req.Path.String()+"\n"+ + "Given Value: "+v.ValueString()+"\n"+ + "Error: "+err.Error(), + ) + + return + } } // Implementation of the validation.ValidateableParameter interface func (v CustomStringValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { - if v.IsNull() || v.IsUnknown() { - return - } - - err := v.validate(v.ValueString()) - - if err != nil { - resp.Error = function.NewArgumentFuncError( - req.Position, - "Invalid RFC 3339 String Value: "+ - "An unexpected error occurred while converting a string value that was expected to be RFC 3339 format. "+ - "The RFC 3339 string format is YYYY-MM-DDTHH:MM:SSZ, such as 2006-01-02T15:04:05Z or 2006-01-02T15:04:05+07:00.\n\n"+ - fmt.Sprintf("Position: %d", req.Position)+"\n"+ - "Given Value: "+v.ValueString()+"\n"+ - "Error: "+err.Error(), - ) - } + if v.IsNull() || v.IsUnknown() { + return + } + + err := v.validate(v.ValueString()) + + if err != nil { + resp.Error = function.NewArgumentFuncError( + req.Position, + "Invalid RFC 3339 String Value: "+ + "An unexpected error occurred while converting a string value that was expected to be RFC 3339 format. "+ + "The RFC 3339 string format is YYYY-MM-DDTHH:MM:SSZ, such as 2006-01-02T15:04:05Z or 2006-01-02T15:04:05+07:00.\n\n"+ + fmt.Sprintf("Position: %d", req.Position)+"\n"+ + "Given Value: "+v.ValueString()+"\n"+ + "Error: "+err.Error(), + ) + } } func (v CustomStringValue) validate(in string) error { - _, err := time.Parse(time.RFC3339, in) + _, err := time.Parse(time.RFC3339, in) - return err + return err } ``` diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index c210ffe60..37bd2ee5c 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -251,15 +251,16 @@ schema.StringAttribute{ ### Defining Value Validation -To support validation for a custom value type, you must implement [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) for attribute validation, or [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) for provider-defined function parameter validation. Both interfaces can be implemented if the same custom type is used for both attributes and function parameters. +To support validation for a custom value type, you must implement [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) for attribute validation, or [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) for provider-defined function parameter validation. -For example: +Value type-specific interfaces are also provided as a convenience, for example [`validation.StringValuableWithValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableAttribute), and [`validation.StringValuableWithValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableParameter). + +Both interfaces can be implemented if the same custom value type is used for both attributes and function parameters, for example: ```go // Ensure the implementation satisfies the expected interfaces -var _ basetypes.StringValuable = computeInstanceIdentifierType{} -var _ xattr.ValidateableAttribute = computeInstanceIdentifierType{} -var _ validation.ValidateableParameter = computeInstanceIdentifierType{} +var _ validation.StringValuableWithValidateableAttribute = computeInstanceIdentifierValue{} +var _ validation.StringValuableWithValidateableParameter = computeInstanceIdentifierValue{} // Other methods to implement the attr.Value interface are omitted for brevity type computeInstanceIdentifierValue struct { From 399acd1b26d3142fb5632aa84d84c1da52f5e83f Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 4 Apr 2024 16:09:12 +0100 Subject: [PATCH 33/62] Adding changelog entries --- .changes/unreleased/BREAKING CHANGES-20240404-182004.yaml | 5 +++++ .changes/unreleased/FEATURES-20240404-154339.yaml | 5 +++++ .changes/unreleased/FEATURES-20240404-154439.yaml | 6 ++++++ .changes/unreleased/FEATURES-20240404-154553.yaml | 8 ++++++++ .changes/unreleased/FEATURES-20240404-155023.yaml | 8 ++++++++ .changes/unreleased/NOTES-20240404-155606.yaml | 6 ++++++ 6 files changed, 38 insertions(+) create mode 100644 .changes/unreleased/BREAKING CHANGES-20240404-182004.yaml create mode 100644 .changes/unreleased/FEATURES-20240404-154339.yaml create mode 100644 .changes/unreleased/FEATURES-20240404-154439.yaml create mode 100644 .changes/unreleased/FEATURES-20240404-154553.yaml create mode 100644 .changes/unreleased/FEATURES-20240404-155023.yaml create mode 100644 .changes/unreleased/NOTES-20240404-155606.yaml diff --git a/.changes/unreleased/BREAKING CHANGES-20240404-182004.yaml b/.changes/unreleased/BREAKING CHANGES-20240404-182004.yaml new file mode 100644 index 000000000..56477030b --- /dev/null +++ b/.changes/unreleased/BREAKING CHANGES-20240404-182004.yaml @@ -0,0 +1,5 @@ +kind: BREAKING CHANGES +body: 'function: Removed `Definition` type `Parameter()` method' +time: 2024-04-04T18:20:04.534677+01:00 +custom: + Issue: "968" diff --git a/.changes/unreleased/FEATURES-20240404-154339.yaml b/.changes/unreleased/FEATURES-20240404-154339.yaml new file mode 100644 index 000000000..4d1ce742f --- /dev/null +++ b/.changes/unreleased/FEATURES-20240404-154339.yaml @@ -0,0 +1,5 @@ +kind: FEATURES +body: 'attr/xattr: Added `ValidateableAttribute` interface for custom value type implementations' +time: 2024-04-04T15:43:39.796606+01:00 +custom: + Issue: "968" diff --git a/.changes/unreleased/FEATURES-20240404-154439.yaml b/.changes/unreleased/FEATURES-20240404-154439.yaml new file mode 100644 index 000000000..d0f591a0d --- /dev/null +++ b/.changes/unreleased/FEATURES-20240404-154439.yaml @@ -0,0 +1,6 @@ +kind: FEATURES +body: 'types/validation: Added `ValidateableParameter` interface for custom value + type implementations' +time: 2024-04-04T15:44:39.289946+01:00 +custom: + Issue: "968" diff --git a/.changes/unreleased/FEATURES-20240404-154553.yaml b/.changes/unreleased/FEATURES-20240404-154553.yaml new file mode 100644 index 000000000..db3b46932 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240404-154553.yaml @@ -0,0 +1,8 @@ +kind: FEATURES +body: 'types/validation: Added `BoolValuableWithValidateableAttribute`, `Float64ValuableWithValidateableAttribute`, + `Int64ValuableWithValidateableAttribute`, `ListValuableWithValidateableAttribute`, `MapValuableWithValidateableAttribute`, + `NumberValuableWithValidateableAttribute`, `ObjectValuableWithValidateableAttribute`, `SetValuableWithValidateableAttribute`, + and `StringValuableWithValidateableAttribute` interfaces for custom value type-specific implementations' +time: 2024-04-04T15:45:53.376774+01:00 +custom: + Issue: "968" diff --git a/.changes/unreleased/FEATURES-20240404-155023.yaml b/.changes/unreleased/FEATURES-20240404-155023.yaml new file mode 100644 index 000000000..dbe503147 --- /dev/null +++ b/.changes/unreleased/FEATURES-20240404-155023.yaml @@ -0,0 +1,8 @@ +kind: FEATURES +body: 'types/validation: Added `BoolValuableWithValidateableParameter`, `Float64ValuableWithValidateableParameter`, + `Int64ValuableWithValidateableParameter`, `ListValuableWithValidateableParameter`, `MapValuableWithValidateableParameter`, + `NumberValuableWithValidateableParameter`, `ObjectValuableWithValidateableParameter`, `SetValuableWithValidateableParameter`, + and `StringValuableWithValidateableParameter` interfaces for custom value type-specific implementations' +time: 2024-04-04T15:50:23.784389+01:00 +custom: + Issue: "968" diff --git a/.changes/unreleased/NOTES-20240404-155606.yaml b/.changes/unreleased/NOTES-20240404-155606.yaml new file mode 100644 index 000000000..3a4964636 --- /dev/null +++ b/.changes/unreleased/NOTES-20240404-155606.yaml @@ -0,0 +1,6 @@ +kind: NOTES +body: 'attr/xattr: The `TypeWithValidate` interface has been deprecated in preference + of the `ValidateableAttribute` interface' +time: 2024-04-04T15:56:06.494328+01:00 +custom: + Issue: "968" From 07511f69aef335f3c678fe01e853c5ab1c31c288 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Thu, 4 Apr 2024 16:26:51 -0400 Subject: [PATCH 34/62] Add variadic parameter test cases --- internal/fromproto5/arguments_data.go | 5 +- internal/fromproto5/arguments_data_test.go | 250 ++++++++++++++++++++- 2 files changed, 251 insertions(+), 4 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index cc5d85558..887cc2816 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -347,9 +347,8 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def variadicValue, variadicValueDiags := basetypes.NewTupleValue(tupleTypes, tupleValues) - funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, variadicValueDiags)) - - if funcError != nil { + if variadicValueDiags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, variadicValueDiags)) return function.NewArgumentsData(argumentValues), funcError } diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 0a4038618..0efc9af5e 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -1661,8 +1661,256 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), ), }, + "variadicparameter-one": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + }, + ), + }), + }, + "variadicparameter-one-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), + ), + }, + "variadicparameter-multiple": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + basetypes.NewStringValue("false"), + }, + ), + }), + }, + "variadicparameter-multiple-error-single": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("true"), + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), + ), + }, + "variadicparameter-multiple-errors-multiple": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), + function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), + ), + }, + "boolparameter-and-variadicparameter-multiple-error-single": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) - //TODO: Add test cases for variadic parameter + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("true"), + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(2, "Error Diagnostic: string validator error."), + ), + }, } for name, testCase := range testCases { From 90b8f4b02f233d420ef29eff4708a5aaf1d34f1a Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Thu, 4 Apr 2024 16:34:23 -0400 Subject: [PATCH 35/62] Add variadic parameter support and test for `tfprotov6` --- internal/fromproto5/arguments_data.go | 1 - internal/fromproto6/arguments_data.go | 164 ++- internal/fromproto6/arguments_data_test.go | 1525 ++++++++++++++++++++ 3 files changed, 1683 insertions(+), 7 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 887cc2816..870bc207d 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -344,7 +344,6 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def tupleTypes[i] = variadicType tupleValues[i] = val } - variadicValue, variadicValueDiags := basetypes.NewTupleValue(tupleTypes, tupleValues) if variadicValueDiags.HasError() { diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 58fb6e492..dd929c78c 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/validation" ) @@ -56,9 +57,8 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def for position, argument := range arguments { parameter, parameterDiags := definition.Parameter(ctx, position) - funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) - - if funcError != nil { + if parameterDiags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, parameterDiags)) return function.NewArgumentsData(nil), funcError } @@ -162,6 +162,159 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } + switch parameterWithValidators := parameter.(type) { + case function.ParameterWithBoolValidators: + for _, functionValidator := range parameterWithValidators.BoolValidators() { + req := function.BoolRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.Bool), + } + resp := &function.BoolResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithDynamicValidators: + for _, functionValidator := range parameterWithValidators.DynamicValidators() { + req := function.DynamicRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.Dynamic), + } + resp := &function.DynamicResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithFloat64Validators: + for _, functionValidator := range parameterWithValidators.Float64Validators() { + req := function.Float64Request{ + ArgumentPosition: pos, + Value: attrValue.(types.Float64), + } + resp := &function.Float64Response{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithInt64Validators: + for _, functionValidator := range parameterWithValidators.Int64Validators() { + req := function.Int64Request{ + ArgumentPosition: pos, + Value: attrValue.(types.Int64), + } + resp := &function.Int64Response{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithListValidators: + for _, functionValidator := range parameterWithValidators.ListValidators() { + req := function.ListRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.List), + } + resp := &function.ListResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithMapValidators: + for _, functionValidator := range parameterWithValidators.MapValidators() { + req := function.MapRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.Map), + } + resp := &function.MapResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithNumberValidators: + for _, functionValidator := range parameterWithValidators.NumberValidators() { + req := function.NumberRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.Number), + } + resp := &function.NumberResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithObjectValidators: + for _, functionValidator := range parameterWithValidators.ObjectValidators() { + req := function.ObjectRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.Object), + } + resp := &function.ObjectResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithSetValidators: + for _, functionValidator := range parameterWithValidators.SetValidators() { + req := function.SetRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.Set), + } + resp := &function.SetResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + case function.ParameterWithStringValidators: + for _, functionValidator := range parameterWithValidators.StringValidators() { + req := function.StringRequest{ + ArgumentPosition: pos, + Value: attrValue.(types.String), + } + resp := &function.StringResponse{} + functionValidator.Validate(ctx, req, resp) + if resp.Error != nil { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + resp.Error.Error(), + )) + } + } + } + if definition.VariadicParameter != nil && position >= len(definition.Parameters) { variadicValues = append(variadicValues, attrValue) @@ -193,9 +346,8 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } variadicValue, variadicValueDiags := basetypes.NewTupleValue(tupleTypes, tupleValues) - funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, variadicValueDiags)) - - if funcError != nil { + if variadicValueDiags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, variadicValueDiags)) return function.NewArgumentsData(argumentValues), funcError } diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index fcca1de63..46ccb7035 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -5,6 +5,7 @@ package fromproto6_test import ( "context" + "math/big" "testing" "github.com/google/go-cmp/cmp" @@ -15,6 +16,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes" + "github.com/hashicorp/terraform-plugin-framework/internal/testing/testvalidator" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) @@ -434,3 +437,1525 @@ func TestArgumentsData(t *testing.T) { }) } } + +func TestArgumentsData_ParameterValidators(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + input []*tfprotov6.DynamicValue + definition function.Definition + expected function.ArgumentsData + expectedFuncError *function.FuncError + }{ + "bool-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + }, + "bool-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "bool-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "dynamic-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(true)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + }, + "dynamic-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "dynamic-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "float64-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(1.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + }, + "float64-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(2.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "float64-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(2.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(3.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "int64-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(1) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + }, + "int64-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(2) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "int64-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(2) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(3) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "list-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "list-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "list-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "map-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + }, + "map-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "map-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key1": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "number-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(1)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewNumberValue(big.NewFloat(1)), + }), + }, + "number-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(2)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewNumberValue(big.NewFloat(1)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "number-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(2)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(3)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewNumberValue(big.NewFloat(1)), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "object-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + }, + "object-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "object-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute1": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute1": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "set-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "set-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "set-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "string-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewStringValue("true"), + }), + }, + "string-parameter-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewStringValue("true"), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, + "string-parameter-Validators-multiple-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 1.", + ) + } + }, + }, + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: error 2.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewStringValue("true"), + }), + expectedFuncError: function.NewArgumentFuncError( + 0, + "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "multiple-parameter-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + basetypes.NewStringValue("true"), + }), + }, + "multiple-parameter-Validators-errors": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: bool validator error.", + ) + } + }, + }, + }, + }, + function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + basetypes.NewStringValue("true"), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(0, "Error Diagnostic: bool validator error."), + function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), + ), + }, + "variadicparameter-one": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + }, + ), + }), + }, + "variadicparameter-one-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), + ), + }, + "variadicparameter-multiple": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + basetypes.NewStringValue("false"), + }, + ), + }), + }, + "variadicparameter-multiple-error-single": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("true"), + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), + ), + }, + "variadicparameter-multiple-errors-multiple": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("false"), + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), + function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), + ), + }, + "boolparameter-and-variadicparameter-multiple-error-single": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + DynamicValueMust(tftypes.NewValue(tftypes.String, "false")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + VariadicParameter: function.StringParameter{ + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: string validator error.", + ) + } + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewBoolValue(true), + basetypes.NewTupleValueMust( + []attr.Type{ + basetypes.StringType{}, + basetypes.StringType{}, + }, + []attr.Value{ + basetypes.NewStringValue("true"), + basetypes.NewStringValue("false"), + }, + ), + }), + expectedFuncError: function.ConcatFuncErrors( + function.NewArgumentFuncError(2, "Error Diagnostic: string validator error."), + ), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got, diags := fromproto6.ArgumentsData(context.Background(), testCase.input, testCase.definition) + + if diff := cmp.Diff(got, testCase.expected); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + + if diff := cmp.Diff(diags, testCase.expectedFuncError); diff != "" { + t.Errorf("unexpected diagnostics difference: %s", diff) + } + }) + } +} + +func createListValue(elementType attr.Type, elements []attr.Value) attr.Value { + list, _ := basetypes.NewListValue(elementType, elements) + return list +} + +func createMapValue(elementType attr.Type, elements map[string]attr.Value) attr.Value { + mapVal, _ := basetypes.NewMapValue(elementType, elements) + return mapVal +} + +func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) attr.Value { + object, _ := basetypes.NewObjectValue(attributeTypes, attributes) + return object +} + +func createSetValue(elementType attr.Type, elements []attr.Value) attr.Value { + list, _ := basetypes.NewSetValue(elementType, elements) + return list +} + +func createDynamicValue(value tftypes.Value) *tfprotov6.DynamicValue { + dynamicVal, _ := tfprotov6.NewDynamicValue(tftypes.DynamicPseudoType, value) + return &dynamicVal +} From 209264893f77e1611e197bd2bf1bbfd02f09aac3 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Thu, 4 Apr 2024 16:35:57 -0400 Subject: [PATCH 36/62] Add copyright headers --- function/bool_parameter_validator.go | 3 +++ function/dynamic_parameter_validator.go | 3 +++ function/float64_parameter_validator.go | 3 +++ function/int64_parameter_validator.go | 3 +++ function/list_parameter_validator.go | 3 +++ function/map_parameter_validator.go | 3 +++ function/number_parameter_validator.go | 3 +++ function/object_parameter_validator.go | 3 +++ function/parameter_validation.go | 3 +++ function/set_parameter_validator.go | 3 +++ function/string_parameter_validator.go | 3 +++ 11 files changed, 33 insertions(+) diff --git a/function/bool_parameter_validator.go b/function/bool_parameter_validator.go index 29112b468..ee31a5592 100644 --- a/function/bool_parameter_validator.go +++ b/function/bool_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/dynamic_parameter_validator.go b/function/dynamic_parameter_validator.go index 89332d743..40255628c 100644 --- a/function/dynamic_parameter_validator.go +++ b/function/dynamic_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/float64_parameter_validator.go b/function/float64_parameter_validator.go index e723768d4..2f87112cd 100644 --- a/function/float64_parameter_validator.go +++ b/function/float64_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/int64_parameter_validator.go b/function/int64_parameter_validator.go index fe2c0914a..d9a31610f 100644 --- a/function/int64_parameter_validator.go +++ b/function/int64_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/list_parameter_validator.go b/function/list_parameter_validator.go index 0b3564be9..75682e10e 100644 --- a/function/list_parameter_validator.go +++ b/function/list_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/map_parameter_validator.go b/function/map_parameter_validator.go index 982abe088..54c10b77b 100644 --- a/function/map_parameter_validator.go +++ b/function/map_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/number_parameter_validator.go b/function/number_parameter_validator.go index 2072eb953..5aa4a7d06 100644 --- a/function/number_parameter_validator.go +++ b/function/number_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/object_parameter_validator.go b/function/object_parameter_validator.go index cf3797d6e..01665b29a 100644 --- a/function/object_parameter_validator.go +++ b/function/object_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/parameter_validation.go b/function/parameter_validation.go index e104b3cee..4ee49f1b4 100644 --- a/function/parameter_validation.go +++ b/function/parameter_validation.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function // ParameterWithBoolValidators is an optional interface on Parameter which diff --git a/function/set_parameter_validator.go b/function/set_parameter_validator.go index 1bfbc92b0..55fad305c 100644 --- a/function/set_parameter_validator.go +++ b/function/set_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( diff --git a/function/string_parameter_validator.go b/function/string_parameter_validator.go index dd8a2f797..41f54b59c 100644 --- a/function/string_parameter_validator.go +++ b/function/string_parameter_validator.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package function import ( From b73c0efedbaa30f2822e8c416213157b452c9fea Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Thu, 4 Apr 2024 16:54:46 -0400 Subject: [PATCH 37/62] Resolve `forcetypeassert` linter errors --- internal/fromproto5/arguments_data.go | 150 ++++++++++++++++++++++++-- internal/fromproto6/arguments_data.go | 150 ++++++++++++++++++++++++-- 2 files changed, 280 insertions(+), 20 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 870bc207d..76aa72161 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -165,9 +165,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def switch parameterWithValidators := parameter.(type) { case function.ParameterWithBoolValidators: for _, functionValidator := range parameterWithValidators.BoolValidators() { + boolVal, ok := attrValue.(types.Bool) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Bool at position %d", pos), + )) + + continue + } req := function.BoolRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Bool), + Value: boolVal, } resp := &function.BoolResponse{} functionValidator.Validate(ctx, req, resp) @@ -180,9 +193,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithDynamicValidators: for _, functionValidator := range parameterWithValidators.DynamicValidators() { + dynamicVal, ok := attrValue.(types.Dynamic) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Dynamic at position %d", pos), + )) + + continue + } req := function.DynamicRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Dynamic), + Value: dynamicVal, } resp := &function.DynamicResponse{} functionValidator.Validate(ctx, req, resp) @@ -195,9 +221,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithFloat64Validators: for _, functionValidator := range parameterWithValidators.Float64Validators() { + float64Value, ok := attrValue.(types.Float64) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Float64 at position %d", pos), + )) + + continue + } req := function.Float64Request{ ArgumentPosition: pos, - Value: attrValue.(types.Float64), + Value: float64Value, } resp := &function.Float64Response{} functionValidator.Validate(ctx, req, resp) @@ -210,9 +249,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithInt64Validators: for _, functionValidator := range parameterWithValidators.Int64Validators() { + int64Value, ok := attrValue.(types.Int64) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Int64 at position %d", pos), + )) + + continue + } req := function.Int64Request{ ArgumentPosition: pos, - Value: attrValue.(types.Int64), + Value: int64Value, } resp := &function.Int64Response{} functionValidator.Validate(ctx, req, resp) @@ -225,9 +277,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithListValidators: for _, functionValidator := range parameterWithValidators.ListValidators() { + listValue, ok := attrValue.(types.List) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.List at position %d", pos), + )) + + continue + } req := function.ListRequest{ ArgumentPosition: pos, - Value: attrValue.(types.List), + Value: listValue, } resp := &function.ListResponse{} functionValidator.Validate(ctx, req, resp) @@ -240,9 +305,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithMapValidators: for _, functionValidator := range parameterWithValidators.MapValidators() { + mapValue, ok := attrValue.(types.Map) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Map at position %d", pos), + )) + + continue + } req := function.MapRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Map), + Value: mapValue, } resp := &function.MapResponse{} functionValidator.Validate(ctx, req, resp) @@ -255,9 +333,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithNumberValidators: for _, functionValidator := range parameterWithValidators.NumberValidators() { + numberValue, ok := attrValue.(types.Number) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Number at position %d", pos), + )) + + continue + } req := function.NumberRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Number), + Value: numberValue, } resp := &function.NumberResponse{} functionValidator.Validate(ctx, req, resp) @@ -270,9 +361,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithObjectValidators: for _, functionValidator := range parameterWithValidators.ObjectValidators() { + objectValue, ok := attrValue.(types.Object) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Object at position %d", pos), + )) + + continue + } req := function.ObjectRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Object), + Value: objectValue, } resp := &function.ObjectResponse{} functionValidator.Validate(ctx, req, resp) @@ -285,9 +389,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithSetValidators: for _, functionValidator := range parameterWithValidators.SetValidators() { + setValue, ok := attrValue.(types.Set) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Set at position %d", pos), + )) + + continue + } req := function.SetRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Set), + Value: setValue, } resp := &function.SetResponse{} functionValidator.Validate(ctx, req, resp) @@ -300,9 +417,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithStringValidators: for _, functionValidator := range parameterWithValidators.StringValidators() { + stringValue, ok := attrValue.(types.String) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.String at position %d", pos), + )) + + continue + } req := function.StringRequest{ ArgumentPosition: pos, - Value: attrValue.(types.String), + Value: stringValue, } resp := &function.StringResponse{} functionValidator.Validate(ctx, req, resp) diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index dd929c78c..93956d310 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -165,9 +165,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def switch parameterWithValidators := parameter.(type) { case function.ParameterWithBoolValidators: for _, functionValidator := range parameterWithValidators.BoolValidators() { + boolVal, ok := attrValue.(types.Bool) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Bool at position %d", pos), + )) + + continue + } req := function.BoolRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Bool), + Value: boolVal, } resp := &function.BoolResponse{} functionValidator.Validate(ctx, req, resp) @@ -180,9 +193,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithDynamicValidators: for _, functionValidator := range parameterWithValidators.DynamicValidators() { + dynamicVal, ok := attrValue.(types.Dynamic) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Dynamic at position %d", pos), + )) + + continue + } req := function.DynamicRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Dynamic), + Value: dynamicVal, } resp := &function.DynamicResponse{} functionValidator.Validate(ctx, req, resp) @@ -195,9 +221,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithFloat64Validators: for _, functionValidator := range parameterWithValidators.Float64Validators() { + float64Value, ok := attrValue.(types.Float64) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Float64 at position %d", pos), + )) + + continue + } req := function.Float64Request{ ArgumentPosition: pos, - Value: attrValue.(types.Float64), + Value: float64Value, } resp := &function.Float64Response{} functionValidator.Validate(ctx, req, resp) @@ -210,9 +249,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithInt64Validators: for _, functionValidator := range parameterWithValidators.Int64Validators() { + int64Value, ok := attrValue.(types.Int64) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Int64 at position %d", pos), + )) + + continue + } req := function.Int64Request{ ArgumentPosition: pos, - Value: attrValue.(types.Int64), + Value: int64Value, } resp := &function.Int64Response{} functionValidator.Validate(ctx, req, resp) @@ -225,9 +277,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithListValidators: for _, functionValidator := range parameterWithValidators.ListValidators() { + listValue, ok := attrValue.(types.List) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.List at position %d", pos), + )) + + continue + } req := function.ListRequest{ ArgumentPosition: pos, - Value: attrValue.(types.List), + Value: listValue, } resp := &function.ListResponse{} functionValidator.Validate(ctx, req, resp) @@ -240,9 +305,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithMapValidators: for _, functionValidator := range parameterWithValidators.MapValidators() { + mapValue, ok := attrValue.(types.Map) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Map at position %d", pos), + )) + + continue + } req := function.MapRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Map), + Value: mapValue, } resp := &function.MapResponse{} functionValidator.Validate(ctx, req, resp) @@ -255,9 +333,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithNumberValidators: for _, functionValidator := range parameterWithValidators.NumberValidators() { + numberValue, ok := attrValue.(types.Number) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Number at position %d", pos), + )) + + continue + } req := function.NumberRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Number), + Value: numberValue, } resp := &function.NumberResponse{} functionValidator.Validate(ctx, req, resp) @@ -270,9 +361,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithObjectValidators: for _, functionValidator := range parameterWithValidators.ObjectValidators() { + objectValue, ok := attrValue.(types.Object) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Object at position %d", pos), + )) + + continue + } req := function.ObjectRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Object), + Value: objectValue, } resp := &function.ObjectResponse{} functionValidator.Validate(ctx, req, resp) @@ -285,9 +389,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithSetValidators: for _, functionValidator := range parameterWithValidators.SetValidators() { + setValue, ok := attrValue.(types.Set) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.Set at position %d", pos), + )) + + continue + } req := function.SetRequest{ ArgumentPosition: pos, - Value: attrValue.(types.Set), + Value: setValue, } resp := &function.SetResponse{} functionValidator.Validate(ctx, req, resp) @@ -300,9 +417,22 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithStringValidators: for _, functionValidator := range parameterWithValidators.StringValidators() { + stringValue, ok := attrValue.(types.String) + if !ok { + funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( + pos, + "Invalid Argument Type: "+ + "An unexpected error was encountered when converting the function argument from the protocol type. "+ + "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ + "Please report this to the provider developer:\n\n"+ + fmt.Sprintf("Expected types.String at position %d", pos), + )) + + continue + } req := function.StringRequest{ ArgumentPosition: pos, - Value: attrValue.(types.String), + Value: stringValue, } resp := &function.StringResponse{} functionValidator.Validate(ctx, req, resp) From 01321ea15875c8dd967fcafc883b14f98ce4f71e Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Thu, 4 Apr 2024 17:30:30 -0400 Subject: [PATCH 38/62] Resolve test failures from merge --- internal/fromproto5/arguments_data_test.go | 16 ++++++++++++---- internal/fromproto6/arguments_data_test.go | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 27317c299..0594e9d07 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -532,7 +532,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", @@ -547,7 +549,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateParameterError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "This is a function error", @@ -616,7 +620,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.\nError Diagnostic: This is an error.", @@ -632,7 +638,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateParameterError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "This is a function error\nThis is a function error", diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index c903d260f..70ebeffb9 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -535,7 +535,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", @@ -550,7 +552,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateParameterError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "This is a function error", @@ -619,7 +623,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.\nError Diagnostic: This is an error.", @@ -635,7 +641,9 @@ func TestArgumentsData(t *testing.T) { CustomType: testtypes.StringTypeWithValidateParameterError{}, }, }, - expected: function.NewArgumentsData(nil), + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewTupleValueMust([]attr.Type{}, []attr.Value{}), + }), expectedFuncError: function.NewArgumentFuncError( 0, "This is a function error\nThis is a function error", From 6a323731dce6c622b82601299c3bb92d33f010b1 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 5 Apr 2024 08:27:26 +0100 Subject: [PATCH 39/62] function: Remove unused Definition.Parameter() method --- function/definition.go | 35 ----- function/definition_test.go | 133 ------------------- internal/fwfunction/xfwfunction/parameter.go | 2 +- 3 files changed, 1 insertion(+), 169 deletions(-) diff --git a/function/definition.go b/function/definition.go index 87dd45fb2..4796a1207 100644 --- a/function/definition.go +++ b/function/definition.go @@ -51,41 +51,6 @@ type Definition struct { DeprecationMessage string } -// Parameter returns the Parameter for a given argument position. This may be -// from the Parameters field or, if defined, the VariadicParameter field. An -// error diagnostic is raised if the position is outside the expected arguments. -func (d Definition) Parameter(ctx context.Context, position int) (Parameter, diag.Diagnostics) { - if d.VariadicParameter != nil && position >= len(d.Parameters) { - return d.VariadicParameter, nil - } - - if len(d.Parameters) == 0 { - return nil, diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Invalid Parameter Position for Definition", - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Function does not implement parameters.\n"+ - fmt.Sprintf("Given position: %d", position), - ), - } - } - - if position >= len(d.Parameters) { - return nil, diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Invalid Parameter Position for Definition", - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Max argument position: %d\n", len(d.Parameters)-1)+ - fmt.Sprintf("Given position: %d", position), - ), - } - } - - return d.Parameters[position], nil -} - // ValidateImplementation contains logic for validating the provider-defined // implementation of the definition to prevent unexpected errors or panics. This // logic runs during the GetProviderSchema RPC, or via provider-defined unit diff --git a/function/definition_test.go b/function/definition_test.go index d2f75b99f..87dcc27e6 100644 --- a/function/definition_test.go +++ b/function/definition_test.go @@ -14,139 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -func TestDefinitionParameter(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - definition function.Definition - position int - expected function.Parameter - expectedDiagnostics diag.Diagnostics - }{ - "none": { - definition: function.Definition{ - // no Parameters or VariadicParameter - }, - position: 0, - expected: nil, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Invalid Parameter Position for Definition", - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Function does not implement parameters.\n"+ - "Given position: 0", - ), - }, - }, - "parameters-first": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - function.Int64Parameter{}, - function.StringParameter{}, - }, - }, - position: 0, - expected: function.BoolParameter{}, - }, - "parameters-last": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - function.Int64Parameter{}, - function.StringParameter{}, - }, - }, - position: 2, - expected: function.StringParameter{}, - }, - "parameters-middle": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - function.Int64Parameter{}, - function.StringParameter{}, - }, - }, - position: 1, - expected: function.Int64Parameter{}, - }, - "parameters-only": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - }, - position: 0, - expected: function.BoolParameter{}, - }, - "parameters-over": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - }, - position: 1, - expected: nil, - expectedDiagnostics: diag.Diagnostics{ - diag.NewErrorDiagnostic( - "Invalid Parameter Position for Definition", - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Max argument position: 0\n"+ - "Given position: 1", - ), - }, - }, - "variadicparameter-and-parameters-select-parameter": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - VariadicParameter: function.StringParameter{}, - }, - position: 0, - expected: function.BoolParameter{}, - }, - "variadicparameter-and-parameters-select-variadicparameter": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - VariadicParameter: function.StringParameter{}, - }, - position: 1, - expected: function.StringParameter{}, - }, - "variadicparameter-only": { - definition: function.Definition{ - VariadicParameter: function.StringParameter{}, - }, - position: 0, - expected: function.StringParameter{}, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got, diags := testCase.definition.Parameter(context.Background(), testCase.position) - - if diff := cmp.Diff(got, testCase.expected); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - - if diff := cmp.Diff(diags, testCase.expectedDiagnostics); diff != "" { - t.Errorf("unexpected diagnostics difference: %s", diff) - } - }) - } -} - func TestDefinitionValidateImplementation(t *testing.T) { t.Parallel() diff --git a/internal/fwfunction/xfwfunction/parameter.go b/internal/fwfunction/xfwfunction/parameter.go index 35377650b..d3aed85ba 100644 --- a/internal/fwfunction/xfwfunction/parameter.go +++ b/internal/fwfunction/xfwfunction/parameter.go @@ -12,7 +12,7 @@ import ( // Parameter returns the Parameter for a given argument position. This may be // from the Parameters field or, if defined, the VariadicParameter field. An -// error diagnostic is raised if the position is outside the expected arguments. +// error is raised if the position is outside the expected arguments. func Parameter(ctx context.Context, d function.Definition, position int) (function.Parameter, *function.FuncError) { if d.VariadicParameter != nil && position >= len(d.Parameters) { return d.VariadicParameter, nil From c758c9c7bda81c24ed2359c86116278e9c96d48a Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 5 Apr 2024 08:59:23 +0100 Subject: [PATCH 40/62] attr/xattr: Remove TODO --- attr/xattr/attribute.go | 1 - 1 file changed, 1 deletion(-) diff --git a/attr/xattr/attribute.go b/attr/xattr/attribute.go index 84afb0b63..57278b24f 100644 --- a/attr/xattr/attribute.go +++ b/attr/xattr/attribute.go @@ -1,7 +1,6 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -// TODO: Just putting here for the moment to get rid of import cycle. package xattr import ( From fb75b1934ab478d4bb94c6e8ba1d9a4ebcdf3af1 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 5 Apr 2024 09:30:29 +0100 Subject: [PATCH 41/62] attr/xattr: Modify deprecation comment --- attr/xattr/type.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/attr/xattr/type.go b/attr/xattr/type.go index c7e5b0f83..eaf33bc78 100644 --- a/attr/xattr/type.go +++ b/attr/xattr/type.go @@ -16,8 +16,7 @@ import ( // TypeWithValidate extends the attr.Type interface to include a Validate // method, used to bundle consistent validation logic with the Type. // -// Deprecated: Use the value type-specific AttributeWithValidate and -// ParameterWithValidate interfaces in the validation package instead. +// Deprecated: Use the ValidateableAttribute interface instead. type TypeWithValidate interface { attr.Type From 6f49065d7ec9e6b5ab6050eb5c6edbb1d8dfbe68 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 5 Apr 2024 09:48:58 +0100 Subject: [PATCH 42/62] fwschemadata: Reordering logging calls --- internal/fwschemadata/data_set_at_path.go | 6 +++--- internal/fwschemadata/data_value.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/fwschemadata/data_set_at_path.go b/internal/fwschemadata/data_set_at_path.go index 66c07ed71..211e75c1c 100644 --- a/internal/fwschemadata/data_set_at_path.go +++ b/internal/fwschemadata/data_set_at_path.go @@ -131,7 +131,7 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d return diags } -// SetAttributeTransformFunc recursively creates a value based on the current +// SetAtPathTransformFunc recursively creates a value based on the current // Plan values along the path. If the value at the path does not yet exist, // this will perform recursion to add the child value to a parent value, // creating the parent value if necessary. @@ -237,10 +237,10 @@ func (d Data) SetAtPathTransformFunc(ctx context.Context, path path.Path, tfVal &resp, ) - logging.FrameworkTrace(ctx, "Called provider defined Value ValidateAttribute") - diags.Append(resp.Diagnostics...) + logging.FrameworkTrace(ctx, "Called provider defined Value ValidateAttribute") + if diags.HasError() { return nil, diags } diff --git a/internal/fwschemadata/data_value.go b/internal/fwschemadata/data_value.go index 79e148626..65e3336a0 100644 --- a/internal/fwschemadata/data_value.go +++ b/internal/fwschemadata/data_value.go @@ -103,10 +103,10 @@ func (d Data) ValueAtPath(ctx context.Context, schemaPath path.Path) (attr.Value &resp, ) - logging.FrameworkTrace(ctx, "Called provider defined Value ValidateAttribute") - diags.Append(resp.Diagnostics...) + logging.FrameworkTrace(ctx, "Called provider defined Value ValidateAttribute") + if diags.HasError() { return nil, diags } From 288078a98e7dd05379704b5906478a84d6f4ef6d Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Fri, 5 Apr 2024 18:46:06 -0400 Subject: [PATCH 43/62] Add changelog entries --- .changes/unreleased/FEATURES-20240405-183917.yaml | 7 +++++++ .changes/unreleased/FEATURES-20240405-184527.yaml | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 .changes/unreleased/FEATURES-20240405-183917.yaml create mode 100644 .changes/unreleased/FEATURES-20240405-184527.yaml diff --git a/.changes/unreleased/FEATURES-20240405-183917.yaml b/.changes/unreleased/FEATURES-20240405-183917.yaml new file mode 100644 index 000000000..9a939efcf --- /dev/null +++ b/.changes/unreleased/FEATURES-20240405-183917.yaml @@ -0,0 +1,7 @@ +kind: FEATURES +body: '`function`: Add `BoolValidator`, `DynamicValidator`, `Float64Validator`, `Int64Validator`, + `ListValidator`, `MapValidator`, `NumberValidator`, `ObjectValidator`, `SetValidator`, + and `StringValidator` interfaces for custom type parameter validation implementations' +time: 2024-04-05T18:39:17.640444-04:00 +custom: + Issue: "971" diff --git a/.changes/unreleased/FEATURES-20240405-184527.yaml b/.changes/unreleased/FEATURES-20240405-184527.yaml new file mode 100644 index 000000000..a78216a5f --- /dev/null +++ b/.changes/unreleased/FEATURES-20240405-184527.yaml @@ -0,0 +1,9 @@ +kind: FEATURES +body: '`function`: Add `ParameterWithBoolValidators`, `ParameterWithInt64Validators`, + `ParameterWithFloat64Validators`, `ParameterWithDynamicValidators`, `ParameterWithListValidators`, + `ParameterWithMapValidators`, `ParameterWithNumberValidators`, `ParameterWithObjectValidators`, + `ParameterWithSetValidators`, and `ParameterWithStringValidators` interfaces for + custom type-specific parameter support for validation' +time: 2024-04-05T18:45:27.979266-04:00 +custom: + Issue: "971" From dcdc8ee54e70d63c373207dd2ee2329fed43bd54 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Mon, 8 Apr 2024 17:03:08 -0400 Subject: [PATCH 44/62] Skip appending parameter value if validation fails --- internal/fromproto5/arguments_data.go | 4 + internal/fromproto5/arguments_data_test.go | 87 ++++++---------------- internal/fromproto6/arguments_data.go | 4 + internal/fromproto6/arguments_data_test.go | 87 ++++++---------------- 4 files changed, 50 insertions(+), 132 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 97d213a73..d9be0da36 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -449,6 +449,10 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def continue } + if funcError != nil { + continue + } + argumentValues = append(argumentValues, attrValue) } diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 0594e9d07..81d1176da 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -789,9 +789,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewBoolValue(true), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -834,9 +832,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewBoolValue(true), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -896,9 +892,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewDynamicValue(types.BoolValue(true)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -941,9 +935,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewDynamicValue(types.BoolValue(true)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1003,9 +995,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewFloat64Value(1.0), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1048,9 +1038,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewFloat64Value(1.0), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1110,9 +1098,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewInt64Value(1), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1155,9 +1141,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewInt64Value(1), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1220,9 +1204,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1268,9 +1250,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1335,9 +1315,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1384,9 +1362,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1446,9 +1422,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewNumberValue(big.NewFloat(1)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1491,9 +1465,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewNumberValue(big.NewFloat(1)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1566,10 +1538,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, - map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1622,10 +1591,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, - map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1688,9 +1654,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1736,9 +1700,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1798,9 +1760,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewStringValue("true"), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1843,9 +1803,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewStringValue("true"), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ @@ -1943,10 +1901,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewBoolValue(true), - basetypes.NewStringValue("true"), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: bool validator error."), function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index d04aa5704..88f9b5163 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -449,6 +449,10 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def continue } + if funcError != nil { + continue + } + argumentValues = append(argumentValues, attrValue) } diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index 70ebeffb9..e64168601 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -792,9 +792,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewBoolValue(true), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -837,9 +835,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewBoolValue(true), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -899,9 +895,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewDynamicValue(types.BoolValue(true)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -944,9 +938,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewDynamicValue(types.BoolValue(true)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1006,9 +998,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewFloat64Value(1.0), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1051,9 +1041,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewFloat64Value(1.0), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1113,9 +1101,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewInt64Value(1), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1158,9 +1144,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewInt64Value(1), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1223,9 +1207,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1271,9 +1253,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1338,9 +1318,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1387,9 +1365,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1449,9 +1425,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewNumberValue(big.NewFloat(1)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1494,9 +1468,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewNumberValue(big.NewFloat(1)), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1569,10 +1541,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, - map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1625,10 +1594,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, - map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1691,9 +1657,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1739,9 +1703,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1801,9 +1763,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewStringValue("true"), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1846,9 +1806,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewStringValue("true"), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ @@ -1946,10 +1904,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewBoolValue(true), - basetypes.NewStringValue("true"), - }), + expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: bool validator error."), function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), From e26cde9d1a1a912e008366d504e5dee4598e96f7 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 09:07:56 +0100 Subject: [PATCH 45/62] fromproto5+fromproto6: Inline logic from Parameter() function in ArgumentsData() function --- internal/fromproto5/arguments_data.go | 66 +++++++- internal/fromproto6/arguments_data.go | 31 +++- internal/fwfunction/xfwfunction/doc.go | 6 - internal/fwfunction/xfwfunction/parameter.go | 46 ------ .../fwfunction/xfwfunction/parameter_test.go | 145 ------------------ 5 files changed, 85 insertions(+), 209 deletions(-) delete mode 100644 internal/fwfunction/xfwfunction/doc.go delete mode 100644 internal/fwfunction/xfwfunction/parameter.go delete mode 100644 internal/fwfunction/xfwfunction/parameter_test.go diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 959a1a797..ce5d0ee8f 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -12,7 +12,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/function" - "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -55,16 +54,36 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def var funcError *function.FuncError for position, argument := range arguments { - parameter, parameterFuncError := xfwfunction.Parameter(ctx, definition, position) + var parameter function.Parameter + pos := int64(position) - if parameterFuncError != nil { - return function.NewArgumentsData(nil), function.ConcatFuncErrors(funcError, parameterFuncError) + switch { + case definition.VariadicParameter != nil && position >= len(definition.Parameters): + parameter = definition.VariadicParameter + case len(definition.Parameters) == 0: + return function.NewArgumentsData(nil), function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + "Function does not implement parameters.\n"+ + fmt.Sprintf("Given position: %d", position), + ) + case position >= len(definition.Parameters): + return function.NewArgumentsData(nil), function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Max argument position: %d\n", len(definition.Parameters)-1)+ + fmt.Sprintf("Given position: %d", position), + ) + default: + parameter = definition.Parameters[position] } parameterType := parameter.GetType() - pos := int64(position) - if parameterType == nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -202,3 +221,38 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def return function.NewArgumentsData(argumentValues), funcError } + +// Parameter returns the Parameter for a given argument position. This may be +// from the Parameters field or, if defined, the VariadicParameter field. An +// error is raised if the position is outside the expected arguments. +func Parameter(ctx context.Context, d function.Definition, position int) (function.Parameter, *function.FuncError) { + if d.VariadicParameter != nil && position >= len(d.Parameters) { + return d.VariadicParameter, nil + } + + pos := int64(position) + + if len(d.Parameters) == 0 { + return nil, function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + "Function does not implement parameters.\n"+ + fmt.Sprintf("Given position: %d", position), + ) + } + + if position >= len(d.Parameters) { + return nil, function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Max argument position: %d\n", len(d.Parameters)-1)+ + fmt.Sprintf("Given position: %d", position), + ) + } + + return d.Parameters[position], nil +} diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 267ce7eb5..247e506be 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -12,7 +12,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/function" - "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -55,16 +54,36 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def var funcError *function.FuncError for position, argument := range arguments { - parameter, parameterFuncError := xfwfunction.Parameter(ctx, definition, position) + var parameter function.Parameter + pos := int64(position) - if parameterFuncError != nil { - return function.NewArgumentsData(nil), function.ConcatFuncErrors(funcError, parameterFuncError) + switch { + case definition.VariadicParameter != nil && position >= len(definition.Parameters): + parameter = definition.VariadicParameter + case len(definition.Parameters) == 0: + return function.NewArgumentsData(nil), function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + "Function does not implement parameters.\n"+ + fmt.Sprintf("Given position: %d", position), + ) + case position >= len(definition.Parameters): + return function.NewArgumentsData(nil), function.NewArgumentFuncError( + pos, + "Invalid Parameter Position for Definition: "+ + "When determining the parameter for the given argument position, an invalid value was given. "+ + "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Max argument position: %d\n", len(definition.Parameters)-1)+ + fmt.Sprintf("Given position: %d", position), + ) + default: + parameter = definition.Parameters[position] } parameterType := parameter.GetType() - pos := int64(position) - if parameterType == nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, diff --git a/internal/fwfunction/xfwfunction/doc.go b/internal/fwfunction/xfwfunction/doc.go deleted file mode 100644 index 18baa8635..000000000 --- a/internal/fwfunction/xfwfunction/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// Package xfwfunction contains additional functions for use with provider defined functions. -// This package is separate from the fwfunction package to prevent import cycles. -package xfwfunction diff --git a/internal/fwfunction/xfwfunction/parameter.go b/internal/fwfunction/xfwfunction/parameter.go deleted file mode 100644 index d3aed85ba..000000000 --- a/internal/fwfunction/xfwfunction/parameter.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package xfwfunction - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-framework/function" -) - -// Parameter returns the Parameter for a given argument position. This may be -// from the Parameters field or, if defined, the VariadicParameter field. An -// error is raised if the position is outside the expected arguments. -func Parameter(ctx context.Context, d function.Definition, position int) (function.Parameter, *function.FuncError) { - if d.VariadicParameter != nil && position >= len(d.Parameters) { - return d.VariadicParameter, nil - } - - pos := int64(position) - - if len(d.Parameters) == 0 { - return nil, function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Function does not implement parameters.\n"+ - fmt.Sprintf("Given position: %d", position), - ) - } - - if position >= len(d.Parameters) { - return nil, function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Max argument position: %d\n", len(d.Parameters)-1)+ - fmt.Sprintf("Given position: %d", position), - ) - } - - return d.Parameters[position], nil -} diff --git a/internal/fwfunction/xfwfunction/parameter_test.go b/internal/fwfunction/xfwfunction/parameter_test.go deleted file mode 100644 index ad96d2783..000000000 --- a/internal/fwfunction/xfwfunction/parameter_test.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package xfwfunction_test - -import ( - "context" - "testing" - - "github.com/google/go-cmp/cmp" - - "github.com/hashicorp/terraform-plugin-framework/function" - "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" -) - -func TestParameter(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - definition function.Definition - position int - expected function.Parameter - expectedFuncError *function.FuncError - }{ - "none": { - definition: function.Definition{ - // no Parameters or VariadicParameter - }, - position: 0, - expected: nil, - expectedFuncError: function.NewArgumentFuncError( - int64(0), - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Function does not implement parameters.\n"+ - "Given position: 0", - ), - }, - "parameters-first": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - function.Int64Parameter{}, - function.StringParameter{}, - }, - }, - position: 0, - expected: function.BoolParameter{}, - }, - "parameters-last": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - function.Int64Parameter{}, - function.StringParameter{}, - }, - }, - position: 2, - expected: function.StringParameter{}, - }, - "parameters-middle": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - function.Int64Parameter{}, - function.StringParameter{}, - }, - }, - position: 1, - expected: function.Int64Parameter{}, - }, - "parameters-only": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - }, - position: 0, - expected: function.BoolParameter{}, - }, - "parameters-over": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - }, - position: 1, - expected: nil, - expectedFuncError: function.NewArgumentFuncError( - int64(1), - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Max argument position: 0\n"+ - "Given position: 1", - ), - }, - "variadicparameter-and-parameters-select-parameter": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - VariadicParameter: function.StringParameter{}, - }, - position: 0, - expected: function.BoolParameter{}, - }, - "variadicparameter-and-parameters-select-variadicparameter": { - definition: function.Definition{ - Parameters: []function.Parameter{ - function.BoolParameter{}, - }, - VariadicParameter: function.StringParameter{}, - }, - position: 1, - expected: function.StringParameter{}, - }, - "variadicparameter-only": { - definition: function.Definition{ - VariadicParameter: function.StringParameter{}, - }, - position: 0, - expected: function.StringParameter{}, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got, funcError := xfwfunction.Parameter(context.Background(), testCase.definition, testCase.position) - - if diff := cmp.Diff(got, testCase.expected); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - - if diff := cmp.Diff(funcError, testCase.expectedFuncError); diff != "" { - t.Errorf("unexpected diagnostics difference: %s", diff) - } - }) - } -} From 24db3f2660bde5707830c49eda52a2feb32d4b2a Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 09:24:36 +0100 Subject: [PATCH 46/62] Remove value type-specific interfaces for ValuableWithValidateableAttribute and ValuableWithValidateableParameter --- .../unreleased/FEATURES-20240404-154553.yaml | 8 ------ .../unreleased/FEATURES-20240404-155023.yaml | 8 ------ types/validation/bool_value.go | 27 ------------------- types/validation/float64_value.go | 27 ------------------- types/validation/int64_value.go | 27 ------------------- types/validation/list_value.go | 27 ------------------- types/validation/map_value.go | 27 ------------------- types/validation/number_value.go | 27 ------------------- types/validation/object_value.go | 27 ------------------- types/validation/set_value.go | 27 ------------------- types/validation/string_value.go | 27 ------------------- .../framework/handling-data/types/custom.mdx | 2 -- website/docs/plugin/framework/validation.mdx | 9 ++++--- 13 files changed, 5 insertions(+), 265 deletions(-) delete mode 100644 .changes/unreleased/FEATURES-20240404-154553.yaml delete mode 100644 .changes/unreleased/FEATURES-20240404-155023.yaml delete mode 100644 types/validation/bool_value.go delete mode 100644 types/validation/float64_value.go delete mode 100644 types/validation/int64_value.go delete mode 100644 types/validation/list_value.go delete mode 100644 types/validation/map_value.go delete mode 100644 types/validation/number_value.go delete mode 100644 types/validation/object_value.go delete mode 100644 types/validation/set_value.go delete mode 100644 types/validation/string_value.go diff --git a/.changes/unreleased/FEATURES-20240404-154553.yaml b/.changes/unreleased/FEATURES-20240404-154553.yaml deleted file mode 100644 index db3b46932..000000000 --- a/.changes/unreleased/FEATURES-20240404-154553.yaml +++ /dev/null @@ -1,8 +0,0 @@ -kind: FEATURES -body: 'types/validation: Added `BoolValuableWithValidateableAttribute`, `Float64ValuableWithValidateableAttribute`, - `Int64ValuableWithValidateableAttribute`, `ListValuableWithValidateableAttribute`, `MapValuableWithValidateableAttribute`, - `NumberValuableWithValidateableAttribute`, `ObjectValuableWithValidateableAttribute`, `SetValuableWithValidateableAttribute`, - and `StringValuableWithValidateableAttribute` interfaces for custom value type-specific implementations' -time: 2024-04-04T15:45:53.376774+01:00 -custom: - Issue: "968" diff --git a/.changes/unreleased/FEATURES-20240404-155023.yaml b/.changes/unreleased/FEATURES-20240404-155023.yaml deleted file mode 100644 index dbe503147..000000000 --- a/.changes/unreleased/FEATURES-20240404-155023.yaml +++ /dev/null @@ -1,8 +0,0 @@ -kind: FEATURES -body: 'types/validation: Added `BoolValuableWithValidateableParameter`, `Float64ValuableWithValidateableParameter`, - `Int64ValuableWithValidateableParameter`, `ListValuableWithValidateableParameter`, `MapValuableWithValidateableParameter`, - `NumberValuableWithValidateableParameter`, `ObjectValuableWithValidateableParameter`, `SetValuableWithValidateableParameter`, - and `StringValuableWithValidateableParameter` interfaces for custom value type-specific implementations' -time: 2024-04-04T15:50:23.784389+01:00 -custom: - Issue: "968" diff --git a/types/validation/bool_value.go b/types/validation/bool_value.go deleted file mode 100644 index bebae323b..000000000 --- a/types/validation/bool_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// BoolValuableWithValidateableAttribute extends the basetypes.BoolValuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type BoolValuableWithValidateableAttribute interface { - basetypes.BoolValuable - - xattr.ValidateableAttribute -} - -// BoolValuableWithValidateableParameter extends the basetypes.BoolValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type BoolValuableWithValidateableParameter interface { - basetypes.BoolValuable - - ValidateableParameter -} diff --git a/types/validation/float64_value.go b/types/validation/float64_value.go deleted file mode 100644 index 8dc119f33..000000000 --- a/types/validation/float64_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// Float64ValuableWithValidateableAttribute extends the basetypes.Float64Valuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type Float64ValuableWithValidateableAttribute interface { - basetypes.Float64Valuable - - xattr.ValidateableAttribute -} - -// Float64ValuableWithValidateableParameter extends the basetypes.Float64Valuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type Float64ValuableWithValidateableParameter interface { - basetypes.Float64Valuable - - ValidateableParameter -} diff --git a/types/validation/int64_value.go b/types/validation/int64_value.go deleted file mode 100644 index 5e0fa55ea..000000000 --- a/types/validation/int64_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// Int64ValuableWithValidateableAttribute extends the basetypes.Int64Valuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type Int64ValuableWithValidateableAttribute interface { - basetypes.Int64Valuable - - xattr.ValidateableAttribute -} - -// Int64ValuableWithValidateableParameter extends the basetypes.Int64Valuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type Int64ValuableWithValidateableParameter interface { - basetypes.Int64Valuable - - ValidateableParameter -} diff --git a/types/validation/list_value.go b/types/validation/list_value.go deleted file mode 100644 index c2ce54d3b..000000000 --- a/types/validation/list_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// ListValuableWithValidateableAttribute extends the basetypes.ListValuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type ListValuableWithValidateableAttribute interface { - basetypes.ListValuable - - xattr.ValidateableAttribute -} - -// ListValuableWithValidateableParameter extends the basetypes.ListValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type ListValuableWithValidateableParameter interface { - basetypes.ListValuable - - ValidateableParameter -} diff --git a/types/validation/map_value.go b/types/validation/map_value.go deleted file mode 100644 index 501708494..000000000 --- a/types/validation/map_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// MapValuableWithValidateableAttribute extends the basetypes.MapValuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type MapValuableWithValidateableAttribute interface { - basetypes.MapValuable - - xattr.ValidateableAttribute -} - -// MapValuableWithValidateableParameter extends the basetypes.MapValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type MapValuableWithValidateableParameter interface { - basetypes.MapValuable - - ValidateableParameter -} diff --git a/types/validation/number_value.go b/types/validation/number_value.go deleted file mode 100644 index 9f6fb0f9c..000000000 --- a/types/validation/number_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// NumberValuableWithValidateableAttribute extends the basetypes.NumberValuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type NumberValuableWithValidateableAttribute interface { - basetypes.NumberValuable - - xattr.ValidateableAttribute -} - -// NumberValuableWithValidateableParameter extends the basetypes.NumberValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type NumberValuableWithValidateableParameter interface { - basetypes.NumberValuable - - ValidateableParameter -} diff --git a/types/validation/object_value.go b/types/validation/object_value.go deleted file mode 100644 index 2e361934e..000000000 --- a/types/validation/object_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// ObjectValuableWithValidateableAttribute extends the basetypes.ObjectValuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type ObjectValuableWithValidateableAttribute interface { - basetypes.ObjectValuable - - xattr.ValidateableAttribute -} - -// ObjectValuableWithValidateableParameter extends the basetypes.ObjectValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type ObjectValuableWithValidateableParameter interface { - basetypes.ObjectValuable - - ValidateableParameter -} diff --git a/types/validation/set_value.go b/types/validation/set_value.go deleted file mode 100644 index 2564a35f7..000000000 --- a/types/validation/set_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// SetValuableWithValidateableAttribute extends the basetypes.SetValuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type SetValuableWithValidateableAttribute interface { - basetypes.SetValuable - - xattr.ValidateableAttribute -} - -// SetValuableWithValidateableParameter extends the basetypes.SetValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type SetValuableWithValidateableParameter interface { - basetypes.SetValuable - - ValidateableParameter -} diff --git a/types/validation/string_value.go b/types/validation/string_value.go deleted file mode 100644 index 8f888b7df..000000000 --- a/types/validation/string_value.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr/xattr" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// StringValuableWithValidateableAttribute extends the basetypes.StringValuable interface to include a -// xattr.ValidateableAttribute interface, used to bundle consistent attribute validation logic with -// the Value. -type StringValuableWithValidateableAttribute interface { - basetypes.StringValuable - - xattr.ValidateableAttribute -} - -// StringValuableWithValidateableParameter extends the basetypes.StringValuable interface to include a -// ValidateableParameter interface, used to bundle consistent parameter validation logic with -// the Value. -type StringValuableWithValidateableParameter interface { - basetypes.StringValuable - - ValidateableParameter -} diff --git a/website/docs/plugin/framework/handling-data/types/custom.mdx b/website/docs/plugin/framework/handling-data/types/custom.mdx index 99eab103f..ecea2f67a 100644 --- a/website/docs/plugin/framework/handling-data/types/custom.mdx +++ b/website/docs/plugin/framework/handling-data/types/custom.mdx @@ -316,8 +316,6 @@ Implement the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/githu Immplement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. -Value type-specific interfaces are also provided as a convenience, for example [`validation.StringValuableWithValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableAttribute), and [`validation.StringValuableWithValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableParameter). - If the custom value type is to be used for both schema attribute values and provider-defined function parameters, implement both interfaces. ```go diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index 37bd2ee5c..4d5c914d0 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -253,14 +253,15 @@ schema.StringAttribute{ To support validation for a custom value type, you must implement [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) for attribute validation, or [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) for provider-defined function parameter validation. -Value type-specific interfaces are also provided as a convenience, for example [`validation.StringValuableWithValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableAttribute), and [`validation.StringValuableWithValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#StringValuableWithValidateableParameter). - Both interfaces can be implemented if the same custom value type is used for both attributes and function parameters, for example: ```go // Ensure the implementation satisfies the expected interfaces -var _ validation.StringValuableWithValidateableAttribute = computeInstanceIdentifierValue{} -var _ validation.StringValuableWithValidateableParameter = computeInstanceIdentifierValue{} +var ( + _ basetypes.StringValuable = computeInstanceIdentifierValue{} + _ xattr.ValidateableAttribute = computeInstanceIdentifierValue{} + _ validation.ValidateableParameter = computeInstanceIdentifierValue{} +) // Other methods to implement the attr.Value interface are omitted for brevity type computeInstanceIdentifierValue struct { From 62837882215911c41406abbb3545e7af665e978c Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 09:41:39 +0100 Subject: [PATCH 47/62] website: Adding documentation for parameter validation into parameters page --- .../framework/functions/parameters/index.mdx | 29 ++++++++++++++++++- .../framework/handling-data/types/custom.mdx | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/website/docs/plugin/framework/functions/parameters/index.mdx b/website/docs/plugin/framework/functions/parameters/index.mdx index 2b2b6538c..c61e513c0 100644 --- a/website/docs/plugin/framework/functions/parameters/index.mdx +++ b/website/docs/plugin/framework/functions/parameters/index.mdx @@ -97,4 +97,31 @@ Parameter names are used in runtime errors to highlight which parameter is causi ## Parameter Validation -Parameter validation handling is enabled by using a custom value type which implements the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter). Refer to [Custom Types](/terraform/plugin/framework/handling-data/types/custom) for further details on creating provider-defined types and values \ No newline at end of file +Validation handling for provider-defined function parameters can be enabled by using [custom types](/terraform/plugin/framework/handling-data/types/custom#validation). + +Implement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. + +```go +// Implementation of the validation.ValidateableParameter interface +func (v CustomStringValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { + if v.IsNull() || v.IsUnknown() { + return + } + + _, err := time.Parse(time.RFC3339, v.ValueString()) + + if err != nil { + resp.Error = function.NewArgumentFuncError( + req.Position, + "Invalid RFC 3339 String Value: "+ + "An unexpected error occurred while converting a string value that was expected to be RFC 3339 format. "+ + "The RFC 3339 string format is YYYY-MM-DDTHH:MM:SSZ, such as 2006-01-02T15:04:05Z or 2006-01-02T15:04:05+07:00.\n\n"+ + fmt.Sprintf("Position: %d", req.Position)+"\n"+ + "Given Value: "+v.ValueString()+"\n"+ + "Error: "+err.Error(), + ) + } +} +``` + +Refer to [Custom Types](/terraform/plugin/framework/handling-data/types/custom) for further details on creating provider-defined types and values \ No newline at end of file diff --git a/website/docs/plugin/framework/handling-data/types/custom.mdx b/website/docs/plugin/framework/handling-data/types/custom.mdx index ecea2f67a..7435597f6 100644 --- a/website/docs/plugin/framework/handling-data/types/custom.mdx +++ b/website/docs/plugin/framework/handling-data/types/custom.mdx @@ -314,7 +314,7 @@ Validation handling in custom value types can be enabled for schema attribute va Implement the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) on the custom value type to define and enable validation handling for a schema attribute, which will automatically raise warning and/or error diagnostics when a value is determined to be invalid. -Immplement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. +Implement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. If the custom value type is to be used for both schema attribute values and provider-defined function parameters, implement both interfaces. From 83293bd5f7e01a49fa177cfd4e060c9b3c39a102 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 11:32:02 +0100 Subject: [PATCH 48/62] function: Moving ValidateableParameter interface to function package --- .../unreleased/FEATURES-20240404-154439.yaml | 2 +- function/parameter.go | 26 ++++++++++++++ internal/fromproto5/arguments_data.go | 7 ++-- internal/fromproto6/arguments_data.go | 7 ++-- .../testtypes/boolwithvalidateparameter.go | 5 ++- .../testtypes/stringwithvalidateparameter.go | 5 ++- types/validation/doc.go | 5 --- types/validation/parameter.go | 34 ------------------- .../framework/functions/parameters/index.mdx | 4 +-- .../framework/handling-data/types/custom.mdx | 6 ++-- website/docs/plugin/framework/validation.mdx | 8 ++--- 11 files changed, 46 insertions(+), 63 deletions(-) delete mode 100644 types/validation/doc.go delete mode 100644 types/validation/parameter.go diff --git a/.changes/unreleased/FEATURES-20240404-154439.yaml b/.changes/unreleased/FEATURES-20240404-154439.yaml index d0f591a0d..adc5392bc 100644 --- a/.changes/unreleased/FEATURES-20240404-154439.yaml +++ b/.changes/unreleased/FEATURES-20240404-154439.yaml @@ -1,5 +1,5 @@ kind: FEATURES -body: 'types/validation: Added `ValidateableParameter` interface for custom value +body: 'function: Added `ValidateableParameter` interface for custom value type implementations' time: 2024-04-04T15:44:39.289946+01:00 custom: diff --git a/function/parameter.go b/function/parameter.go index e5add8828..78b84d818 100644 --- a/function/parameter.go +++ b/function/parameter.go @@ -4,6 +4,8 @@ package function import ( + "context" + "github.com/hashicorp/terraform-plugin-framework/attr" ) @@ -38,3 +40,27 @@ type Parameter interface { // Function type Run method. GetType() attr.Type } + +// ValidateableParameter defines an interface for validating a parameter value. +type ValidateableParameter interface { + // ValidateParameter returns any error generated during validation + // of the parameter. It is generally used to check the data format and ensure + // that it complies with the requirements of the Value. + ValidateParameter(context.Context, ValidateParameterRequest, *ValidateParameterResponse) +} + +// ValidateParameterRequest represents a request for the Value to call its +// validation logic. An instance of this request struct is supplied as an +// argument to the Value type ValidateParameter method. +type ValidateParameterRequest struct { + // Position is the zero-ordered position of the parameter being validated. + Position int64 +} + +// ValidateParameterResponse represents a response to a ValidateParameterRequest. +// An instance of this response struct is supplied as an argument to the +// ValidateParameter method. +type ValidateParameterResponse struct { + // Error is a function error generated during validation of the Value. + Error *FuncError +} diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index ce5d0ee8f..81b33afc0 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-framework/types/validation" ) // ArgumentsData returns the ArgumentsData for a given []*tfprotov5.DynamicValue @@ -133,14 +132,14 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 switch t := attrValue.(type) { - case validation.ValidateableParameter: - resp := validation.ValidateParameterResponse{} + case function.ValidateableParameter: + resp := function.ValidateParameterResponse{} logging.FrameworkTrace(ctx, "Parameter value implements ValidateableParameter") logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateParameter") t.ValidateParameter(ctx, - validation.ValidateParameterRequest{ + function.ValidateParameterRequest{ Position: pos, }, &resp, diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 247e506be..5ead38a69 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-framework/types/validation" ) // ArgumentsData returns the ArgumentsData for a given []*tfprotov6.DynamicValue @@ -133,14 +132,14 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/589 // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/893 switch t := attrValue.(type) { - case validation.ValidateableParameter: - resp := validation.ValidateParameterResponse{} + case function.ValidateableParameter: + resp := function.ValidateParameterResponse{} logging.FrameworkTrace(ctx, "Parameter value implements ValidateableParameter") logging.FrameworkTrace(ctx, "Calling provider defined Value ValidateParameter") t.ValidateParameter(ctx, - validation.ValidateParameterRequest{ + function.ValidateParameterRequest{ Position: pos, }, &resp, diff --git a/internal/testing/testtypes/boolwithvalidateparameter.go b/internal/testing/testtypes/boolwithvalidateparameter.go index 3bb07894f..7b6cc7f1e 100644 --- a/internal/testing/testtypes/boolwithvalidateparameter.go +++ b/internal/testing/testtypes/boolwithvalidateparameter.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" - "github.com/hashicorp/terraform-plugin-framework/types/validation" ) type BoolTypeWithValidateParameterError struct { @@ -44,12 +43,12 @@ func (t BoolTypeWithValidateParameterError) ValueFromTerraform(ctx context.Conte }, nil } -var _ validation.ValidateableParameter = BoolValueWithValidateParameterError{} +var _ function.ValidateableParameter = BoolValueWithValidateParameterError{} type BoolValueWithValidateParameterError struct { Bool } -func (v BoolValueWithValidateParameterError) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { +func (v BoolValueWithValidateParameterError) ValidateParameter(ctx context.Context, req function.ValidateParameterRequest, resp *function.ValidateParameterResponse) { resp.Error = function.NewArgumentFuncError(req.Position, "This is a function error") } diff --git a/internal/testing/testtypes/stringwithvalidateparameter.go b/internal/testing/testtypes/stringwithvalidateparameter.go index 8d6beec42..751bbcd47 100644 --- a/internal/testing/testtypes/stringwithvalidateparameter.go +++ b/internal/testing/testtypes/stringwithvalidateparameter.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/function" - "github.com/hashicorp/terraform-plugin-framework/types/validation" ) type StringTypeWithValidateParameterError struct { @@ -44,7 +43,7 @@ func (t StringTypeWithValidateParameterError) ValueFromTerraform(ctx context.Con }, nil } -var _ validation.ValidateableParameter = StringValueWithValidateParameterError{} +var _ function.ValidateableParameter = StringValueWithValidateParameterError{} type StringValueWithValidateParameterError struct { InternalString String @@ -80,6 +79,6 @@ func (v StringValueWithValidateParameterError) String() string { return v.InternalString.String() } -func (v StringValueWithValidateParameterError) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { +func (v StringValueWithValidateParameterError) ValidateParameter(ctx context.Context, req function.ValidateParameterRequest, resp *function.ValidateParameterResponse) { resp.Error = function.NewArgumentFuncError(req.Position, "This is a function error") } diff --git a/types/validation/doc.go b/types/validation/doc.go deleted file mode 100644 index 24ced450b..000000000 --- a/types/validation/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// Package validation contains additional interfaces for base types. -package validation diff --git a/types/validation/parameter.go b/types/validation/parameter.go deleted file mode 100644 index 273520a33..000000000 --- a/types/validation/parameter.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package validation - -import ( - "context" - - "github.com/hashicorp/terraform-plugin-framework/function" -) - -// ValidateableParameter defines an interface for validating a parameter value. -type ValidateableParameter interface { - // ValidateParameter returns any error generated during validation - // of the parameter. It is generally used to check the data format and ensure - // that it complies with the requirements of the Value. - ValidateParameter(context.Context, ValidateParameterRequest, *ValidateParameterResponse) -} - -// ValidateParameterRequest represents a request for the Value to call its -// validation logic. An instance of this request struct is supplied as an -// argument to the Value type ValidateParameter method. -type ValidateParameterRequest struct { - // Position is the zero-ordered position of the parameter being validated. - Position int64 -} - -// ValidateParameterResponse represents a response to a ValidateParameterRequest. -// An instance of this response struct is supplied as an argument to the -// ValidateParameter method. -type ValidateParameterResponse struct { - // Error is a function error generated during validation of the Value. - Error *function.FuncError -} diff --git a/website/docs/plugin/framework/functions/parameters/index.mdx b/website/docs/plugin/framework/functions/parameters/index.mdx index c61e513c0..264362a40 100644 --- a/website/docs/plugin/framework/functions/parameters/index.mdx +++ b/website/docs/plugin/framework/functions/parameters/index.mdx @@ -99,10 +99,10 @@ Parameter names are used in runtime errors to highlight which parameter is causi Validation handling for provider-defined function parameters can be enabled by using [custom types](/terraform/plugin/framework/handling-data/types/custom#validation). -Implement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. +Implement the [`function.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. ```go -// Implementation of the validation.ValidateableParameter interface +// Implementation of the function.ValidateableParameter interface func (v CustomStringValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { if v.IsNull() || v.IsUnknown() { return diff --git a/website/docs/plugin/framework/handling-data/types/custom.mdx b/website/docs/plugin/framework/handling-data/types/custom.mdx index 7435597f6..1d028f737 100644 --- a/website/docs/plugin/framework/handling-data/types/custom.mdx +++ b/website/docs/plugin/framework/handling-data/types/custom.mdx @@ -314,7 +314,7 @@ Validation handling in custom value types can be enabled for schema attribute va Implement the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) on the custom value type to define and enable validation handling for a schema attribute, which will automatically raise warning and/or error diagnostics when a value is determined to be invalid. -Implement the [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. +Implement the [`function.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ValidateableParameter) on the custom value type to define and enable validation handling for a provider-defined function parameter, which will automatically raise an error when a value is determined to be invalid. If the custom value type is to be used for both schema attribute values and provider-defined function parameters, implement both interfaces. @@ -342,7 +342,7 @@ func (v CustomStringValue) ValidateAttribute(ctx context.Context, req xattr.Vali } } -// Implementation of the validation.ValidateableParameter interface +// Implementation of the function.ValidateableParameter interface func (v CustomStringValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { if v.IsNull() || v.IsUnknown() { return @@ -376,7 +376,7 @@ func (v CustomStringValue) validate(in string) error { `Value` validation should be used in preference to `Type` validation. Refer to [Value Validation](#value-validation) for more information. -The [`xattr.TypeWithValidate` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate) has been deprecated. Use the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute), and [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) instead. +The [`xattr.TypeWithValidate` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate) has been deprecated. Use the [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute), and [`function.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ValidateableParameter) instead. diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index 4d5c914d0..a2239459d 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -251,7 +251,7 @@ schema.StringAttribute{ ### Defining Value Validation -To support validation for a custom value type, you must implement [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) for attribute validation, or [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) for provider-defined function parameter validation. +To support validation for a custom value type, you must implement [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) for attribute validation, or [`function.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ValidateableParameter) for provider-defined function parameter validation. Both interfaces can be implemented if the same custom value type is used for both attributes and function parameters, for example: @@ -260,7 +260,7 @@ Both interfaces can be implemented if the same custom value type is used for bot var ( _ basetypes.StringValuable = computeInstanceIdentifierValue{} _ xattr.ValidateableAttribute = computeInstanceIdentifierValue{} - _ validation.ValidateableParameter = computeInstanceIdentifierValue{} + _ function.ValidateableParameter = computeInstanceIdentifierValue{} ) // Other methods to implement the attr.Value interface are omitted for brevity @@ -285,7 +285,7 @@ func (v computeInstanceIdentifierValue) ValidateAttribute(ctx context.Context, r } } -// Implementation of the validation.ValidateableParameter interface +// Implementation of the function.ValidateableParameter interface func (v computeInstanceIdentifierValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { if v.IsNull() || v.IsUnknown() { return @@ -337,7 +337,7 @@ schema.StringAttribute{ -The [`xattr.TypeWithValidate` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate) has been deprecated. Refer to [Defining Value Validation](#defining-value-validation) for more information about using [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute), and [`validation.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/validation#ValidateableParameter) instead. +The [`xattr.TypeWithValidate` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#TypeWithValidate) has been deprecated. Refer to [Defining Value Validation](#defining-value-validation) for more information about using [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute), and [`function.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ValidateableParameter) instead. From 75e30e53dec211d8e2e0e6238daaa047199e849d Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 11:40:20 +0100 Subject: [PATCH 49/62] Amend docs --- .changes/unreleased/NOTES-20240404-155606.yaml | 3 ++- attr/xattr/type.go | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.changes/unreleased/NOTES-20240404-155606.yaml b/.changes/unreleased/NOTES-20240404-155606.yaml index 3a4964636..baf0885a4 100644 --- a/.changes/unreleased/NOTES-20240404-155606.yaml +++ b/.changes/unreleased/NOTES-20240404-155606.yaml @@ -1,6 +1,7 @@ kind: NOTES body: 'attr/xattr: The `TypeWithValidate` interface has been deprecated in preference - of the `ValidateableAttribute` interface' + of the `ValidateableAttribute` interface. A `ValidatableParameter` interface has + also been added to the `function` package' time: 2024-04-04T15:56:06.494328+01:00 custom: Issue: "968" diff --git a/attr/xattr/type.go b/attr/xattr/type.go index eaf33bc78..1dd534fa6 100644 --- a/attr/xattr/type.go +++ b/attr/xattr/type.go @@ -16,7 +16,9 @@ import ( // TypeWithValidate extends the attr.Type interface to include a Validate // method, used to bundle consistent validation logic with the Type. // -// Deprecated: Use the ValidateableAttribute interface instead. +// Deprecated: Use the ValidateableAttribute interface instead for schema +// attribute validation. Use the function.ValidateableParameter interface +// for provider-defined function parameter validation. type TypeWithValidate interface { attr.Type From 6c517b184d8daf6cdbbda8f70f19ac884774b03c Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 14:11:08 +0100 Subject: [PATCH 50/62] Apply suggestions from code review Co-authored-by: Austin Valle --- function/parameter.go | 10 +++++----- .../plugin/framework/functions/parameters/index.mdx | 2 +- .../plugin/framework/handling-data/types/custom.mdx | 2 +- website/docs/plugin/framework/validation.mdx | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/function/parameter.go b/function/parameter.go index 78b84d818..791711f90 100644 --- a/function/parameter.go +++ b/function/parameter.go @@ -44,14 +44,14 @@ type Parameter interface { // ValidateableParameter defines an interface for validating a parameter value. type ValidateableParameter interface { // ValidateParameter returns any error generated during validation - // of the parameter. It is generally used to check the data format and ensure - // that it complies with the requirements of the Value. + // of the parameter. It is generally used to check the data format and ensure + // that it complies with the requirements of the attr.Value. ValidateParameter(context.Context, ValidateParameterRequest, *ValidateParameterResponse) } -// ValidateParameterRequest represents a request for the Value to call its +// ValidateParameterRequest represents a request for the attr.Value to call its // validation logic. An instance of this request struct is supplied as an -// argument to the Value type ValidateParameter method. +// argument to the attr.Value type ValidateParameter method. type ValidateParameterRequest struct { // Position is the zero-ordered position of the parameter being validated. Position int64 @@ -61,6 +61,6 @@ type ValidateParameterRequest struct { // An instance of this response struct is supplied as an argument to the // ValidateParameter method. type ValidateParameterResponse struct { - // Error is a function error generated during validation of the Value. + // Error is a function error generated during validation of the attr.Value. Error *FuncError } diff --git a/website/docs/plugin/framework/functions/parameters/index.mdx b/website/docs/plugin/framework/functions/parameters/index.mdx index 264362a40..d055141d9 100644 --- a/website/docs/plugin/framework/functions/parameters/index.mdx +++ b/website/docs/plugin/framework/functions/parameters/index.mdx @@ -103,7 +103,7 @@ Implement the [`function.ValidateableParameter` interface](https://pkg.go.dev/gi ```go // Implementation of the function.ValidateableParameter interface -func (v CustomStringValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { +func (v CustomStringValue) ValidateParameter(ctx context.Context, req function.ValidateParameterRequest, resp *function.ValidateParameterResponse) { if v.IsNull() || v.IsUnknown() { return } diff --git a/website/docs/plugin/framework/handling-data/types/custom.mdx b/website/docs/plugin/framework/handling-data/types/custom.mdx index 1d028f737..a82914fc2 100644 --- a/website/docs/plugin/framework/handling-data/types/custom.mdx +++ b/website/docs/plugin/framework/handling-data/types/custom.mdx @@ -343,7 +343,7 @@ func (v CustomStringValue) ValidateAttribute(ctx context.Context, req xattr.Vali } // Implementation of the function.ValidateableParameter interface -func (v CustomStringValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { +func (v CustomStringValue) ValidateParameter(ctx context.Context, req function.ValidateParameterRequest, resp *function.ValidateParameterResponse) { if v.IsNull() || v.IsUnknown() { return } diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index a2239459d..ad4d929cb 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -286,7 +286,7 @@ func (v computeInstanceIdentifierValue) ValidateAttribute(ctx context.Context, r } // Implementation of the function.ValidateableParameter interface -func (v computeInstanceIdentifierValue) ValidateParameter(ctx context.Context, req validation.ValidateParameterRequest, resp *validation.ValidateParameterResponse) { +func (v computeInstanceIdentifierValue) ValidateParameter(ctx context.Context, req function.ValidateParameterRequest, resp *function.ValidateParameterResponse) { if v.IsNull() || v.IsUnknown() { return } From c55b74bb5b7c34171fb8151dbe9d3b3aa4b9f2ca Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 15:16:58 +0100 Subject: [PATCH 51/62] fromproto5: Remove unused function --- internal/fromproto5/arguments_data.go | 35 --------------------------- 1 file changed, 35 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 81b33afc0..ae6a0e818 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -220,38 +220,3 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def return function.NewArgumentsData(argumentValues), funcError } - -// Parameter returns the Parameter for a given argument position. This may be -// from the Parameters field or, if defined, the VariadicParameter field. An -// error is raised if the position is outside the expected arguments. -func Parameter(ctx context.Context, d function.Definition, position int) (function.Parameter, *function.FuncError) { - if d.VariadicParameter != nil && position >= len(d.Parameters) { - return d.VariadicParameter, nil - } - - pos := int64(position) - - if len(d.Parameters) == 0 { - return nil, function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Function does not implement parameters.\n"+ - fmt.Sprintf("Given position: %d", position), - ) - } - - if position >= len(d.Parameters) { - return nil, function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Max argument position: %d\n", len(d.Parameters)-1)+ - fmt.Sprintf("Given position: %d", position), - ) - } - - return d.Parameters[position], nil -} From 0d3ff07deb0ac505301937e4f97fec7df95ccb7f Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 15:31:06 +0100 Subject: [PATCH 52/62] fromproto5+fromproto6: Remove unneeded case statements --- internal/fromproto5/arguments_data.go | 18 ------------------ internal/fromproto5/arguments_data_test.go | 7 +++++++ internal/fromproto6/arguments_data.go | 18 ------------------ 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index ae6a0e818..0ae09d5db 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -59,24 +59,6 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def switch { case definition.VariadicParameter != nil && position >= len(definition.Parameters): parameter = definition.VariadicParameter - case len(definition.Parameters) == 0: - return function.NewArgumentsData(nil), function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Function does not implement parameters.\n"+ - fmt.Sprintf("Given position: %d", position), - ) - case position >= len(definition.Parameters): - return function.NewArgumentsData(nil), function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Max argument position: %d\n", len(definition.Parameters)-1)+ - fmt.Sprintf("Given position: %d", position), - ) default: parameter = definition.Parameters[position] } diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 86b9349a4..df634dd1b 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -40,6 +40,13 @@ func TestArgumentsData(t *testing.T) { definition: function.Definition{}, expected: function.ArgumentsData{}, }, + "empty-def": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, nil)), + }, + definition: function.Definition{}, + expected: function.ArgumentsData{}, + }, "mismatched-arguments-too-few-arguments": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, nil)), diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 5ead38a69..18d1949f2 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -59,24 +59,6 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def switch { case definition.VariadicParameter != nil && position >= len(definition.Parameters): parameter = definition.VariadicParameter - case len(definition.Parameters) == 0: - return function.NewArgumentsData(nil), function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - "Function does not implement parameters.\n"+ - fmt.Sprintf("Given position: %d", position), - ) - case position >= len(definition.Parameters): - return function.NewArgumentsData(nil), function.NewArgumentFuncError( - pos, - "Invalid Parameter Position for Definition: "+ - "When determining the parameter for the given argument position, an invalid value was given. "+ - "This is always an issue in the provider code and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Max argument position: %d\n", len(definition.Parameters)-1)+ - fmt.Sprintf("Given position: %d", position), - ) default: parameter = definition.Parameters[position] } From cf398ce338d57fcc63e085325a2b1327d9d41698 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Tue, 9 Apr 2024 15:34:06 +0100 Subject: [PATCH 53/62] fromproto5: Removing errant test case --- internal/fromproto5/arguments_data_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index df634dd1b..86b9349a4 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -40,13 +40,6 @@ func TestArgumentsData(t *testing.T) { definition: function.Definition{}, expected: function.ArgumentsData{}, }, - "empty-def": { - input: []*tfprotov5.DynamicValue{ - DynamicValueMust(tftypes.NewValue(tftypes.Bool, nil)), - }, - definition: function.Definition{}, - expected: function.ArgumentsData{}, - }, "mismatched-arguments-too-few-arguments": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, nil)), From 1f79cbb83db16079c3f3d62c7572186c1766779f Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Tue, 9 Apr 2024 15:03:16 -0400 Subject: [PATCH 54/62] Support parameter validation for custom types --- internal/fromproto5/arguments_data.go | 107 +++- internal/fromproto5/arguments_data_test.go | 684 ++++++++++++++++++++- internal/fromproto6/arguments_data.go | 107 +++- internal/fromproto6/arguments_data_test.go | 684 ++++++++++++++++++++- internal/testing/testtypes/float64.go | 39 ++ internal/testing/testtypes/int64.go | 39 ++ 6 files changed, 1590 insertions(+), 70 deletions(-) create mode 100644 internal/testing/testtypes/float64.go create mode 100644 internal/testing/testtypes/int64.go diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index d9be0da36..13da0f78b 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/validation" ) @@ -163,7 +162,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def switch parameterWithValidators := parameter.(type) { case function.ParameterWithBoolValidators: for _, functionValidator := range parameterWithValidators.BoolValidators() { - boolVal, ok := attrValue.(types.Bool) + boolValuable, ok := attrValue.(basetypes.BoolValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -171,11 +170,16 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Bool at position %d", pos), + fmt.Sprintf("Expected basetypes.BoolValuable at position %d", pos), )) continue } + boolVal, diags := boolValuable.ToBoolValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.BoolRequest{ ArgumentPosition: pos, Value: boolVal, @@ -191,7 +195,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithDynamicValidators: for _, functionValidator := range parameterWithValidators.DynamicValidators() { - dynamicVal, ok := attrValue.(types.Dynamic) + dynamicValuable, ok := attrValue.(basetypes.DynamicValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -199,11 +203,16 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Dynamic at position %d", pos), + fmt.Sprintf("Expected basetypes.DynamicValuable at position %d", pos), )) continue } + dynamicVal, diags := dynamicValuable.ToDynamicValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.DynamicRequest{ ArgumentPosition: pos, Value: dynamicVal, @@ -219,7 +228,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithFloat64Validators: for _, functionValidator := range parameterWithValidators.Float64Validators() { - float64Value, ok := attrValue.(types.Float64) + float64Valuable, ok := attrValue.(basetypes.Float64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -227,14 +236,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Float64 at position %d", pos), + fmt.Sprintf("Expected basetypes.Float64Valuable at position %d", pos), )) continue } + float64Val, diags := float64Valuable.ToFloat64Value(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.Float64Request{ ArgumentPosition: pos, - Value: float64Value, + Value: float64Val, } resp := &function.Float64Response{} functionValidator.Validate(ctx, req, resp) @@ -247,7 +261,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithInt64Validators: for _, functionValidator := range parameterWithValidators.Int64Validators() { - int64Value, ok := attrValue.(types.Int64) + int64Valuable, ok := attrValue.(basetypes.Int64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -255,14 +269,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Int64 at position %d", pos), + fmt.Sprintf("Expected basetypes.Int64Valuable at position %d", pos), )) continue } + int64Val, diags := int64Valuable.ToInt64Value(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.Int64Request{ ArgumentPosition: pos, - Value: int64Value, + Value: int64Val, } resp := &function.Int64Response{} functionValidator.Validate(ctx, req, resp) @@ -275,7 +294,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithListValidators: for _, functionValidator := range parameterWithValidators.ListValidators() { - listValue, ok := attrValue.(types.List) + listValue, ok := attrValue.(basetypes.ListValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -283,14 +302,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.List at position %d", pos), + fmt.Sprintf("Expected basetypes.ListValuable at position %d", pos), )) continue } + listVal, diags := listValue.ToListValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.ListRequest{ ArgumentPosition: pos, - Value: listValue, + Value: listVal, } resp := &function.ListResponse{} functionValidator.Validate(ctx, req, resp) @@ -303,7 +327,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithMapValidators: for _, functionValidator := range parameterWithValidators.MapValidators() { - mapValue, ok := attrValue.(types.Map) + mapValuable, ok := attrValue.(basetypes.MapValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -311,14 +335,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Map at position %d", pos), + fmt.Sprintf("Expected basetypes.MapValuable at position %d", pos), )) continue } + mapVal, diags := mapValuable.ToMapValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.MapRequest{ ArgumentPosition: pos, - Value: mapValue, + Value: mapVal, } resp := &function.MapResponse{} functionValidator.Validate(ctx, req, resp) @@ -331,7 +360,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithNumberValidators: for _, functionValidator := range parameterWithValidators.NumberValidators() { - numberValue, ok := attrValue.(types.Number) + numberValuable, ok := attrValue.(basetypes.NumberValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -339,14 +368,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Number at position %d", pos), + fmt.Sprintf("Expected basetypes.NumberValuable at position %d", pos), )) continue } + numberVal, diags := numberValuable.ToNumberValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.NumberRequest{ ArgumentPosition: pos, - Value: numberValue, + Value: numberVal, } resp := &function.NumberResponse{} functionValidator.Validate(ctx, req, resp) @@ -359,7 +393,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithObjectValidators: for _, functionValidator := range parameterWithValidators.ObjectValidators() { - objectValue, ok := attrValue.(types.Object) + objectValuable, ok := attrValue.(basetypes.ObjectValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -367,14 +401,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Object at position %d", pos), + fmt.Sprintf("Expected basetypes.ObjectValuable at position %d", pos), )) continue } + objectVal, diags := objectValuable.ToObjectValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.ObjectRequest{ ArgumentPosition: pos, - Value: objectValue, + Value: objectVal, } resp := &function.ObjectResponse{} functionValidator.Validate(ctx, req, resp) @@ -387,7 +426,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithSetValidators: for _, functionValidator := range parameterWithValidators.SetValidators() { - setValue, ok := attrValue.(types.Set) + setValuable, ok := attrValue.(basetypes.SetValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -395,14 +434,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Set at position %d", pos), + fmt.Sprintf("Expected basetypes.SetValuable at position %d", pos), )) continue } + setVal, diags := setValuable.ToSetValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.SetRequest{ ArgumentPosition: pos, - Value: setValue, + Value: setVal, } resp := &function.SetResponse{} functionValidator.Validate(ctx, req, resp) @@ -415,7 +459,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } case function.ParameterWithStringValidators: for _, functionValidator := range parameterWithValidators.StringValidators() { - stringValue, ok := attrValue.(types.String) + stringValuable, ok := attrValue.(basetypes.StringValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -423,14 +467,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.String at position %d", pos), + fmt.Sprintf("Expected basetypes.StringValuable at position %d", pos), )) continue } + stringVal, diags := stringValuable.ToStringValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.StringRequest{ ArgumentPosition: pos, - Value: stringValue, + Value: stringVal, } resp := &function.StringResponse{} functionValidator.Validate(ctx, req, resp) diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 81d1176da..30ded953d 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -838,6 +838,69 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "bool-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolType{}, + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Bool{ + Bool: basetypes.NewBoolValue(true), + }, + }), + }, + "bool-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolType{}, + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "dynamic-parameter-Validators": { input: []*tfprotov5.DynamicValue{ createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), @@ -941,6 +1004,67 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "dynamic-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + CustomType: testtypes.DynamicType{}, + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(true)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + }, + "dynamic-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + CustomType: testtypes.DynamicType{}, + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "float64-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), @@ -1044,6 +1168,67 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "float64-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + CustomType: testtypes.Float64Type{}, + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(1.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + }, + "float64-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + CustomType: testtypes.Float64Type{}, + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(2.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "int64-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), @@ -1147,6 +1332,67 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "int64-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + CustomType: testtypes.Int64Type{}, + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(1) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + }, + "int64-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + CustomType: testtypes.Int64Type{}, + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(2) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "list-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), @@ -1256,6 +1502,78 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "list-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + CustomType: testtypes.ListType{ + ListType: types.ListType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "list-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + CustomType: testtypes.ListType{ + ListType: types.ListType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "map-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, @@ -1364,8 +1682,82 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( - 0, "Error Diagnostic: error 1."+ - "\nError Diagnostic: error 2.", + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "map-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + CustomType: testtypes.MapType{ + MapType: types.MapType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + }, + "map-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + CustomType: testtypes.MapType{ + MapType: types.MapType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", ), }, "number-parameter-Validators": { @@ -1471,6 +1863,69 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "number-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + CustomType: testtypes.NumberType{}, + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(1)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Number{ + Number: basetypes.NewNumberValue(big.NewFloat(1)), + }, + }), + }, + "number-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + CustomType: testtypes.NumberType{}, + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(2)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "object-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, @@ -1597,6 +2052,88 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "object-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + CustomType: testtypes.ObjectType{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{"boolAttribute": types.BoolType}, + }, + }, + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + }, + "object-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + CustomType: testtypes.ObjectType{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{"boolAttribute": types.BoolType}, + }, + }, + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "set-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), @@ -1706,6 +2243,78 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "set-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + CustomType: testtypes.SetType{ + SetType: types.SetType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "set-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + CustomType: testtypes.SetType{ + SetType: types.SetType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "string-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), @@ -1810,6 +2419,69 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "string-parameter-custom-type-Validators": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + CustomType: testtypes.StringType{}, + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.String{ + InternalString: basetypes.NewStringValue("true"), + }, + }), + }, + "string-parameter-custom-type-Validators-error": { + input: []*tfprotov5.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + CustomType: testtypes.StringType{}, + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "multiple-parameter-Validators": { input: []*tfprotov5.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), @@ -2178,22 +2850,22 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { } } -func createListValue(elementType attr.Type, elements []attr.Value) attr.Value { +func createListValue(elementType attr.Type, elements []attr.Value) basetypes.ListValue { list, _ := basetypes.NewListValue(elementType, elements) return list } -func createMapValue(elementType attr.Type, elements map[string]attr.Value) attr.Value { +func createMapValue(elementType attr.Type, elements map[string]attr.Value) basetypes.MapValue { mapVal, _ := basetypes.NewMapValue(elementType, elements) return mapVal } -func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) attr.Value { +func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) basetypes.ObjectValue { object, _ := basetypes.NewObjectValue(attributeTypes, attributes) return object } -func createSetValue(elementType attr.Type, elements []attr.Value) attr.Value { +func createSetValue(elementType attr.Type, elements []attr.Value) basetypes.SetValue { list, _ := basetypes.NewSetValue(elementType, elements) return list } diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index 88f9b5163..db6630375 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwfunction/xfwfunction" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-framework/types/validation" ) @@ -163,7 +162,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def switch parameterWithValidators := parameter.(type) { case function.ParameterWithBoolValidators: for _, functionValidator := range parameterWithValidators.BoolValidators() { - boolVal, ok := attrValue.(types.Bool) + boolValuable, ok := attrValue.(basetypes.BoolValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -171,11 +170,16 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Bool at position %d", pos), + fmt.Sprintf("Expected basetypes.BoolValuable at position %d", pos), )) continue } + boolVal, diags := boolValuable.ToBoolValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.BoolRequest{ ArgumentPosition: pos, Value: boolVal, @@ -191,7 +195,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithDynamicValidators: for _, functionValidator := range parameterWithValidators.DynamicValidators() { - dynamicVal, ok := attrValue.(types.Dynamic) + dynamicValuable, ok := attrValue.(basetypes.DynamicValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -199,11 +203,16 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Dynamic at position %d", pos), + fmt.Sprintf("Expected basetypes.DynamicValuable at position %d", pos), )) continue } + dynamicVal, diags := dynamicValuable.ToDynamicValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.DynamicRequest{ ArgumentPosition: pos, Value: dynamicVal, @@ -219,7 +228,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithFloat64Validators: for _, functionValidator := range parameterWithValidators.Float64Validators() { - float64Value, ok := attrValue.(types.Float64) + float64Valuable, ok := attrValue.(basetypes.Float64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -227,14 +236,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Float64 at position %d", pos), + fmt.Sprintf("Expected basetypes.Float64Valuable at position %d", pos), )) continue } + float64Val, diags := float64Valuable.ToFloat64Value(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.Float64Request{ ArgumentPosition: pos, - Value: float64Value, + Value: float64Val, } resp := &function.Float64Response{} functionValidator.Validate(ctx, req, resp) @@ -247,7 +261,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithInt64Validators: for _, functionValidator := range parameterWithValidators.Int64Validators() { - int64Value, ok := attrValue.(types.Int64) + int64Valuable, ok := attrValue.(basetypes.Int64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -255,14 +269,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Int64 at position %d", pos), + fmt.Sprintf("Expected basetypes.Int64Valuable at position %d", pos), )) continue } + int64Val, diags := int64Valuable.ToInt64Value(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.Int64Request{ ArgumentPosition: pos, - Value: int64Value, + Value: int64Val, } resp := &function.Int64Response{} functionValidator.Validate(ctx, req, resp) @@ -275,7 +294,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithListValidators: for _, functionValidator := range parameterWithValidators.ListValidators() { - listValue, ok := attrValue.(types.List) + listValue, ok := attrValue.(basetypes.ListValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -283,14 +302,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.List at position %d", pos), + fmt.Sprintf("Expected basetypes.ListValuable at position %d", pos), )) continue } + listVal, diags := listValue.ToListValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.ListRequest{ ArgumentPosition: pos, - Value: listValue, + Value: listVal, } resp := &function.ListResponse{} functionValidator.Validate(ctx, req, resp) @@ -303,7 +327,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithMapValidators: for _, functionValidator := range parameterWithValidators.MapValidators() { - mapValue, ok := attrValue.(types.Map) + mapValuable, ok := attrValue.(basetypes.MapValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -311,14 +335,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Map at position %d", pos), + fmt.Sprintf("Expected basetypes.MapValuable at position %d", pos), )) continue } + mapVal, diags := mapValuable.ToMapValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.MapRequest{ ArgumentPosition: pos, - Value: mapValue, + Value: mapVal, } resp := &function.MapResponse{} functionValidator.Validate(ctx, req, resp) @@ -331,7 +360,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithNumberValidators: for _, functionValidator := range parameterWithValidators.NumberValidators() { - numberValue, ok := attrValue.(types.Number) + numberValuable, ok := attrValue.(basetypes.NumberValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -339,14 +368,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Number at position %d", pos), + fmt.Sprintf("Expected basetypes.NumberValuable at position %d", pos), )) continue } + numberVal, diags := numberValuable.ToNumberValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.NumberRequest{ ArgumentPosition: pos, - Value: numberValue, + Value: numberVal, } resp := &function.NumberResponse{} functionValidator.Validate(ctx, req, resp) @@ -359,7 +393,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithObjectValidators: for _, functionValidator := range parameterWithValidators.ObjectValidators() { - objectValue, ok := attrValue.(types.Object) + objectValuable, ok := attrValue.(basetypes.ObjectValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -367,14 +401,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Object at position %d", pos), + fmt.Sprintf("Expected basetypes.ObjectValuable at position %d", pos), )) continue } + objectVal, diags := objectValuable.ToObjectValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.ObjectRequest{ ArgumentPosition: pos, - Value: objectValue, + Value: objectVal, } resp := &function.ObjectResponse{} functionValidator.Validate(ctx, req, resp) @@ -387,7 +426,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithSetValidators: for _, functionValidator := range parameterWithValidators.SetValidators() { - setValue, ok := attrValue.(types.Set) + setValuable, ok := attrValue.(basetypes.SetValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -395,14 +434,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.Set at position %d", pos), + fmt.Sprintf("Expected basetypes.SetValuable at position %d", pos), )) continue } + setVal, diags := setValuable.ToSetValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.SetRequest{ ArgumentPosition: pos, - Value: setValue, + Value: setVal, } resp := &function.SetResponse{} functionValidator.Validate(ctx, req, resp) @@ -415,7 +459,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } case function.ParameterWithStringValidators: for _, functionValidator := range parameterWithValidators.StringValidators() { - stringValue, ok := attrValue.(types.String) + stringValuable, ok := attrValue.(basetypes.StringValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -423,14 +467,19 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def "An unexpected error was encountered when converting the function argument from the protocol type. "+ "This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+ "Please report this to the provider developer:\n\n"+ - fmt.Sprintf("Expected types.String at position %d", pos), + fmt.Sprintf("Expected basetypes.StringValuable at position %d", pos), )) continue } + stringVal, diags := stringValuable.ToStringValue(ctx) + if diags.HasError() { + funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) + continue + } req := function.StringRequest{ ArgumentPosition: pos, - Value: stringValue, + Value: stringVal, } resp := &function.StringResponse{} functionValidator.Validate(ctx, req, resp) diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index e64168601..4d835e389 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -841,6 +841,69 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "bool-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolType{}, + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(true) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Bool{ + Bool: basetypes.NewBoolValue(true), + }, + }), + }, + "bool-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.BoolParameter{ + CustomType: testtypes.BoolType{}, + Validators: []function.BoolValidator{ + testvalidator.Bool{ + ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + got := req.Value + expected := types.BoolValue(false) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "dynamic-parameter-Validators": { input: []*tfprotov6.DynamicValue{ createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), @@ -944,6 +1007,67 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "dynamic-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + CustomType: testtypes.DynamicType{}, + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(true)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewDynamicValue(types.BoolValue(true)), + }), + }, + "dynamic-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + createDynamicValue(tftypes.NewValue(tftypes.Bool, true)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.DynamicParameter{ + CustomType: testtypes.DynamicType{}, + Validators: []function.DynamicValidator{ + testvalidator.Dynamic{ + ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + got := req.Value + expected := types.DynamicValue(types.BoolValue(false)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "float64-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), @@ -1047,6 +1171,67 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "float64-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + CustomType: testtypes.Float64Type{}, + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(1.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewFloat64Value(1.0), + }), + }, + "float64-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1.0)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Float64Parameter{ + CustomType: testtypes.Float64Type{}, + Validators: []function.Float64Validator{ + testvalidator.Float64{ + ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + got := req.Value + expected := types.Float64Value(2.0) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "int64-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), @@ -1150,6 +1335,67 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "int64-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + CustomType: testtypes.Int64Type{}, + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(1) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + basetypes.NewInt64Value(1), + }), + }, + "int64-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.Int64Parameter{ + CustomType: testtypes.Int64Type{}, + Validators: []function.Int64Validator{ + testvalidator.Int64{ + ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + got := req.Value + expected := types.Int64Value(2) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "list-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), @@ -1259,6 +1505,78 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "list-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + CustomType: testtypes.ListType{ + ListType: types.ListType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "list-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.List{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ListParameter{ + CustomType: testtypes.ListType{ + ListType: types.ListType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.ListValidator{ + testvalidator.List{ + ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + got := req.Value + expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "map-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, @@ -1367,8 +1685,82 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, expected: function.NewArgumentsData([]attr.Value{}), expectedFuncError: function.NewArgumentFuncError( - 0, "Error Diagnostic: error 1."+ - "\nError Diagnostic: error 2.", + 0, "Error Diagnostic: error 1."+ + "\nError Diagnostic: error 2.", + ), + }, + "map-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + CustomType: testtypes.MapType{ + MapType: types.MapType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + }), + }, + "map-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Map{ElementType: tftypes.Bool}, + map[string]tftypes.Value{"key": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.MapParameter{ + CustomType: testtypes.MapType{ + MapType: types.MapType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.MapValidator{ + testvalidator.Map{ + ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + got := req.Value + expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), + "key2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", ), }, "number-parameter-Validators": { @@ -1474,6 +1866,69 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "number-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + CustomType: testtypes.NumberType{}, + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(1)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.Number{ + Number: basetypes.NewNumberValue(big.NewFloat(1)), + }, + }), + }, + "number-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Number, 1)), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.NumberParameter{ + CustomType: testtypes.NumberType{}, + Validators: []function.NumberValidator{ + testvalidator.Number{ + ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + got := req.Value + expected := types.NumberValue(big.NewFloat(2)) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "object-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, @@ -1600,6 +2055,88 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "object-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + CustomType: testtypes.ObjectType{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{"boolAttribute": types.BoolType}, + }, + }, + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), + }), + }, + "object-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"boolAttribute": tftypes.Bool}}, + map[string]tftypes.Value{"boolAttribute": tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.ObjectParameter{ + CustomType: testtypes.ObjectType{ + ObjectType: types.ObjectType{ + AttrTypes: map[string]attr.Type{"boolAttribute": types.BoolType}, + }, + }, + AttributeTypes: map[string]attr.Type{ + "boolAttribute": types.BoolType, + }, + Validators: []function.ObjectValidator{ + testvalidator.Object{ + ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + got := req.Value + expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, + "boolAttribute2": types.BoolType}, + map[string]attr.Value{"boolAttribute": types.BoolValue(true), + "boolAttribute2": types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "set-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), @@ -1709,6 +2246,78 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "set-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + CustomType: testtypes.SetType{ + SetType: types.SetType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + }), + }, + "set-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.Set{ElementType: tftypes.Bool}, []tftypes.Value{tftypes.NewValue(tftypes.Bool, true)})), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.SetParameter{ + CustomType: testtypes.SetType{ + SetType: types.SetType{ + ElemType: types.BoolType, + }, + }, + ElementType: types.BoolType, + Validators: []function.SetValidator{ + testvalidator.Set{ + ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + got := req.Value + expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), + types.BoolValue(false)}) + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "string-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), @@ -1813,6 +2422,69 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { "\nError Diagnostic: error 2.", ), }, + "string-parameter-custom-type-Validators": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + CustomType: testtypes.StringType{}, + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("true") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{ + testtypes.String{ + InternalString: basetypes.NewStringValue("true"), + }, + }), + }, + "string-parameter-custom-type-Validators-error": { + input: []*tfprotov6.DynamicValue{ + DynamicValueMust(tftypes.NewValue(tftypes.String, "true")), + }, + definition: function.Definition{ + Parameters: []function.Parameter{ + function.StringParameter{ + CustomType: testtypes.StringType{}, + Validators: []function.StringValidator{ + testvalidator.String{ + ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + got := req.Value + expected := types.StringValue("false") + + if !got.Equal(expected) { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + "Error Diagnostic: This is an error.", + ) + } + }, + }, + }, + }, + }, + }, + expected: function.NewArgumentsData([]attr.Value{}), + expectedFuncError: function.NewArgumentFuncError( + 0, "Error Diagnostic: This is an error.", + ), + }, "multiple-parameter-Validators": { input: []*tfprotov6.DynamicValue{ DynamicValueMust(tftypes.NewValue(tftypes.Bool, true)), @@ -2181,22 +2853,22 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { } } -func createListValue(elementType attr.Type, elements []attr.Value) attr.Value { +func createListValue(elementType attr.Type, elements []attr.Value) basetypes.ListValue { list, _ := basetypes.NewListValue(elementType, elements) return list } -func createMapValue(elementType attr.Type, elements map[string]attr.Value) attr.Value { +func createMapValue(elementType attr.Type, elements map[string]attr.Value) basetypes.MapValue { mapVal, _ := basetypes.NewMapValue(elementType, elements) return mapVal } -func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) attr.Value { +func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) basetypes.ObjectValue { object, _ := basetypes.NewObjectValue(attributeTypes, attributes) return object } -func createSetValue(elementType attr.Type, elements []attr.Value) attr.Value { +func createSetValue(elementType attr.Type, elements []attr.Value) basetypes.SetValue { list, _ := basetypes.NewSetValue(elementType, elements) return list } diff --git a/internal/testing/testtypes/float64.go b/internal/testing/testtypes/float64.go new file mode 100644 index 000000000..2c92f6fdd --- /dev/null +++ b/internal/testing/testtypes/float64.go @@ -0,0 +1,39 @@ +package testtypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +var ( + _ basetypes.Float64Typable = Float64Type{} + _ basetypes.Float64Valuable = Float64Value{} +) + +type Float64Type struct { + basetypes.Float64Type +} + +func (t Float64Type) Equal(o attr.Type) bool { + other, ok := o.(Float64Type) + + if !ok { + return false + } + + return t.Float64Type.Equal(other.Float64Type) +} + +type Float64Value struct { + basetypes.Float64Value +} + +func (v Float64Value) Equal(o attr.Value) bool { + other, ok := o.(Float64Value) + + if !ok { + return false + } + + return v.Float64Value.Equal(other.Float64Value) +} diff --git a/internal/testing/testtypes/int64.go b/internal/testing/testtypes/int64.go new file mode 100644 index 000000000..a4b875ea3 --- /dev/null +++ b/internal/testing/testtypes/int64.go @@ -0,0 +1,39 @@ +package testtypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +var ( + _ basetypes.Int64Typable = Int64Type{} + _ basetypes.Int64Valuable = Int64Value{} +) + +type Int64Type struct { + basetypes.Int64Type +} + +func (t Int64Type) Equal(o attr.Type) bool { + other, ok := o.(Int64Type) + + if !ok { + return false + } + + return t.Int64Type.Equal(other.Int64Type) +} + +type Int64Value struct { + basetypes.Int64Value +} + +func (v Int64Value) Equal(o attr.Value) bool { + other, ok := o.(Int64Value) + + if !ok { + return false + } + + return v.Int64Value.Equal(other.Int64Value) +} From 6fce33c0b70b3462272e6d0eb5d6869e1e7be1a3 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Tue, 9 Apr 2024 15:34:05 -0400 Subject: [PATCH 55/62] Refactor parameter validator interface names for clarity. --- function/bool_parameter.go | 5 +- function/bool_parameter_test.go | 12 +- function/bool_parameter_validator.go | 16 +- function/dynamic_parameter.go | 5 +- function/dynamic_parameter_test.go | 12 +- function/dynamic_parameter_validator.go | 16 +- function/float64_parameter.go | 5 +- function/float64_parameter_test.go | 12 +- function/float64_parameter_validator.go | 16 +- function/int64_parameter.go | 5 +- function/int64_parameter_test.go | 12 +- function/int64_parameter_validator.go | 16 +- function/list_parameter.go | 5 +- function/list_parameter_test.go | 12 +- function/list_parameter_validator.go | 16 +- function/map_parameter.go | 5 +- function/map_parameter_test.go | 12 +- function/map_parameter_validator.go | 16 +- function/number_parameter.go | 5 +- function/number_parameter_test.go | 12 +- function/number_parameter_validator.go | 16 +- function/object_parameter.go | 5 +- function/object_parameter_test.go | 12 +- function/object_parameter_validator.go | 16 +- function/parameter_validation.go | 40 ++-- function/set_parameter.go | 5 +- function/set_parameter_test.go | 12 +- function/set_parameter_validator.go | 16 +- function/string_parameter.go | 6 +- function/string_parameter_test.go | 12 +- function/string_parameter_validator.go | 16 +- internal/fromproto5/arguments_data.go | 60 ++--- internal/fromproto5/arguments_data_test.go | 264 ++++++++++----------- internal/fromproto6/arguments_data.go | 60 ++--- internal/fromproto6/arguments_data_test.go | 264 ++++++++++----------- internal/testing/testvalidator/bool.go | 10 +- internal/testing/testvalidator/dynamic.go | 10 +- internal/testing/testvalidator/float64.go | 10 +- internal/testing/testvalidator/int64.go | 10 +- internal/testing/testvalidator/list.go | 10 +- internal/testing/testvalidator/map.go | 10 +- internal/testing/testvalidator/number.go | 10 +- internal/testing/testvalidator/object.go | 10 +- internal/testing/testvalidator/set.go | 10 +- internal/testing/testvalidator/string.go | 10 +- 45 files changed, 564 insertions(+), 555 deletions(-) diff --git a/function/bool_parameter.go b/function/bool_parameter.go index 170e54dd9..67929c31f 100644 --- a/function/bool_parameter.go +++ b/function/bool_parameter.go @@ -74,10 +74,11 @@ type BoolParameter struct { // Validators is a list of bool validators that should be applied to the // parameter. - Validators []BoolValidator + Validators []BoolParameterValidator } -func (p BoolParameter) BoolValidators() []BoolValidator { +// GetValidators returns the list of validators for the parameter. +func (p BoolParameter) GetValidators() []BoolParameterValidator { return p.Validators } diff --git a/function/bool_parameter_test.go b/function/bool_parameter_test.go index 86821c130..bdcf2a32e 100644 --- a/function/bool_parameter_test.go +++ b/function/bool_parameter_test.go @@ -248,7 +248,7 @@ func TestBoolParameterBoolValidators(t *testing.T) { testCases := map[string]struct { parameter function.BoolParameter - expected []function.BoolValidator + expected []function.BoolParameterValidator }{ "unset": { parameter: function.BoolParameter{}, @@ -256,15 +256,15 @@ func TestBoolParameterBoolValidators(t *testing.T) { }, "Validators - empty": { parameter: function.BoolParameter{ - Validators: []function.BoolValidator{}}, - expected: []function.BoolValidator{}, + Validators: []function.BoolParameterValidator{}}, + expected: []function.BoolParameterValidator{}, }, "Validators": { parameter: function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{}, }}, - expected: []function.BoolValidator{ + expected: []function.BoolParameterValidator{ testvalidator.Bool{}, }, }, @@ -276,7 +276,7 @@ func TestBoolParameterBoolValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.BoolValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/bool_parameter_validator.go b/function/bool_parameter_validator.go index ee31a5592..3be3c0f31 100644 --- a/function/bool_parameter_validator.go +++ b/function/bool_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// BoolValidator is a function validator for types.Bool parameters. -type BoolValidator interface { +// BoolParameterValidator is a function validator for types.Bool parameters. +type BoolParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, BoolRequest, *BoolResponse) + // Validate performs the validation. + Validate(context.Context, BoolParameterValidatorRequest, *BoolParameterValidatorResponse) } -// BoolRequest is a request for types.Bool schema validation. -type BoolRequest struct { +// BoolParameterValidatorRequest is a request for types.Bool schema validation. +type BoolParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type BoolRequest struct { Value types.Bool } -// BoolResponse is a response to a BoolRequest. -type BoolResponse struct { +// BoolParameterValidatorResponse is a response to a BoolParameterValidatorRequest. +type BoolParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/dynamic_parameter.go b/function/dynamic_parameter.go index a63b4e73c..cbf2ea33e 100644 --- a/function/dynamic_parameter.go +++ b/function/dynamic_parameter.go @@ -69,10 +69,11 @@ type DynamicParameter struct { // Validators is a list of dynamic validators that should be applied to the // parameter. - Validators []DynamicValidator + Validators []DynamicParameterValidator } -func (p DynamicParameter) DynamicValidators() []DynamicValidator { +// GetValidators returns the list of validators for the parameter. +func (p DynamicParameter) GetValidators() []DynamicParameterValidator { return p.Validators } diff --git a/function/dynamic_parameter_test.go b/function/dynamic_parameter_test.go index a6dddac90..ccf7ab3f1 100644 --- a/function/dynamic_parameter_test.go +++ b/function/dynamic_parameter_test.go @@ -248,7 +248,7 @@ func TestDynamicParameterDynamicValidators(t *testing.T) { testCases := map[string]struct { parameter function.DynamicParameter - expected []function.DynamicValidator + expected []function.DynamicParameterValidator }{ "unset": { parameter: function.DynamicParameter{}, @@ -256,15 +256,15 @@ func TestDynamicParameterDynamicValidators(t *testing.T) { }, "Validators - empty": { parameter: function.DynamicParameter{ - Validators: []function.DynamicValidator{}}, - expected: []function.DynamicValidator{}, + Validators: []function.DynamicParameterValidator{}}, + expected: []function.DynamicParameterValidator{}, }, "Validators": { parameter: function.DynamicParameter{ - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{}, }}, - expected: []function.DynamicValidator{ + expected: []function.DynamicParameterValidator{ testvalidator.Dynamic{}, }, }, @@ -276,7 +276,7 @@ func TestDynamicParameterDynamicValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.DynamicValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/dynamic_parameter_validator.go b/function/dynamic_parameter_validator.go index 40255628c..3e536fa8d 100644 --- a/function/dynamic_parameter_validator.go +++ b/function/dynamic_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// DynamicValidator is a function validator for types.Dynamic parameters. -type DynamicValidator interface { +// DynamicParameterValidator is a function validator for types.Dynamic parameters. +type DynamicParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, DynamicRequest, *DynamicResponse) + // Validate performs the validation. + Validate(context.Context, DynamicParameterValidatorRequest, *DynamicParameterValidatorResponse) } -// DynamicRequest is a request for types.Dynamic schema validation. -type DynamicRequest struct { +// DynamicParameterValidatorRequest is a request for types.Dynamic schema validation. +type DynamicParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type DynamicRequest struct { Value types.Dynamic } -// DynamicResponse is a response to a DynamicRequest. -type DynamicResponse struct { +// DynamicParameterValidatorResponse is a response to a DynamicParameterValidatorRequest. +type DynamicParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/float64_parameter.go b/function/float64_parameter.go index 7d4de5ba7..11e31c7ef 100644 --- a/function/float64_parameter.go +++ b/function/float64_parameter.go @@ -71,10 +71,11 @@ type Float64Parameter struct { // Validators is a list of float64 validators that should be applied to the // parameter. - Validators []Float64Validator + Validators []Float64ParameterValidator } -func (p Float64Parameter) Float64Validators() []Float64Validator { +// GetValidators returns the list of validators for the parameter. +func (p Float64Parameter) GetValidators() []Float64ParameterValidator { return p.Validators } diff --git a/function/float64_parameter_test.go b/function/float64_parameter_test.go index 5db6d9f61..1c364d793 100644 --- a/function/float64_parameter_test.go +++ b/function/float64_parameter_test.go @@ -248,7 +248,7 @@ func TestFloat64ParameterFloat64Validators(t *testing.T) { testCases := map[string]struct { parameter function.Float64Parameter - expected []function.Float64Validator + expected []function.Float64ParameterValidator }{ "unset": { parameter: function.Float64Parameter{}, @@ -256,15 +256,15 @@ func TestFloat64ParameterFloat64Validators(t *testing.T) { }, "Validators - empty": { parameter: function.Float64Parameter{ - Validators: []function.Float64Validator{}}, - expected: []function.Float64Validator{}, + Validators: []function.Float64ParameterValidator{}}, + expected: []function.Float64ParameterValidator{}, }, "Validators": { parameter: function.Float64Parameter{ - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{}, }}, - expected: []function.Float64Validator{ + expected: []function.Float64ParameterValidator{ testvalidator.Float64{}, }, }, @@ -276,7 +276,7 @@ func TestFloat64ParameterFloat64Validators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.Float64Validators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/float64_parameter_validator.go b/function/float64_parameter_validator.go index 2f87112cd..cb8caf5f4 100644 --- a/function/float64_parameter_validator.go +++ b/function/float64_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// Float64Validator is a function validator for types.Float64 parameters. -type Float64Validator interface { +// Float64ParameterValidator is a function validator for types.Float64 parameters. +type Float64ParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, Float64Request, *Float64Response) + // Validate performs the validation. + Validate(context.Context, Float64ParameterValidatorRequest, *Float64ParameterValidatorResponse) } -// Float64Request is a request for types.Float64 schema validation. -type Float64Request struct { +// Float64ParameterValidatorRequest is a request for types.Float64 schema validation. +type Float64ParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type Float64Request struct { Value types.Float64 } -// Float64Response is a response to a Float64Request. -type Float64Response struct { +// Float64ParameterValidatorResponse is a response to a Float64ParameterValidatorRequest. +type Float64ParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/int64_parameter.go b/function/int64_parameter.go index bf0e29ed7..15a9700a7 100644 --- a/function/int64_parameter.go +++ b/function/int64_parameter.go @@ -70,10 +70,11 @@ type Int64Parameter struct { // Validators is a list of int64 validators that should be applied to the // parameter. - Validators []Int64Validator + Validators []Int64ParameterValidator } -func (p Int64Parameter) Int64Validators() []Int64Validator { +// GetValidators returns the list of validators for the parameter. +func (p Int64Parameter) GetValidators() []Int64ParameterValidator { return p.Validators } diff --git a/function/int64_parameter_test.go b/function/int64_parameter_test.go index 07c566c6e..21b608bb2 100644 --- a/function/int64_parameter_test.go +++ b/function/int64_parameter_test.go @@ -248,7 +248,7 @@ func TestInt64ParameterInt64Validators(t *testing.T) { testCases := map[string]struct { parameter function.Int64Parameter - expected []function.Int64Validator + expected []function.Int64ParameterValidator }{ "unset": { parameter: function.Int64Parameter{}, @@ -256,15 +256,15 @@ func TestInt64ParameterInt64Validators(t *testing.T) { }, "Validators - empty": { parameter: function.Int64Parameter{ - Validators: []function.Int64Validator{}}, - expected: []function.Int64Validator{}, + Validators: []function.Int64ParameterValidator{}}, + expected: []function.Int64ParameterValidator{}, }, "Validators": { parameter: function.Int64Parameter{ - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{}, }}, - expected: []function.Int64Validator{ + expected: []function.Int64ParameterValidator{ testvalidator.Int64{}, }, }, @@ -276,7 +276,7 @@ func TestInt64ParameterInt64Validators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.Int64Validators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/int64_parameter_validator.go b/function/int64_parameter_validator.go index d9a31610f..73fc9d3d0 100644 --- a/function/int64_parameter_validator.go +++ b/function/int64_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// Int64Validator is a function validator for types.Int64 parameters. -type Int64Validator interface { +// Int64ParameterValidator is a function validator for types.Int64 parameters. +type Int64ParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, Int64Request, *Int64Response) + // Validate performs the validation. + Validate(context.Context, Int64ParameterValidatorRequest, *Int64ParameterValidatorResponse) } -// Int64Request is a request for types.Int64 schema validation. -type Int64Request struct { +// Int64ParameterValidatorRequest is a request for types.Int64 schema validation. +type Int64ParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type Int64Request struct { Value types.Int64 } -// Int64Response is a response to a Int64Request. -type Int64Response struct { +// Int64ParameterValidatorResponse is a response to a Int64ParameterValidatorRequest. +type Int64ParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/list_parameter.go b/function/list_parameter.go index 9a8fe93b7..cdca5a280 100644 --- a/function/list_parameter.go +++ b/function/list_parameter.go @@ -86,10 +86,11 @@ type ListParameter struct { // Validators is a list of list validators that should be applied to the // parameter. - Validators []ListValidator + Validators []ListParameterValidator } -func (p ListParameter) ListValidators() []ListValidator { +// GetValidators returns the list of validators for the parameter. +func (p ListParameter) GetValidators() []ListParameterValidator { return p.Validators } diff --git a/function/list_parameter_test.go b/function/list_parameter_test.go index 1757083ee..7eb530c41 100644 --- a/function/list_parameter_test.go +++ b/function/list_parameter_test.go @@ -264,7 +264,7 @@ func TestListParameterListValidators(t *testing.T) { testCases := map[string]struct { parameter function.ListParameter - expected []function.ListValidator + expected []function.ListParameterValidator }{ "unset": { parameter: function.ListParameter{}, @@ -272,15 +272,15 @@ func TestListParameterListValidators(t *testing.T) { }, "Validators - empty": { parameter: function.ListParameter{ - Validators: []function.ListValidator{}}, - expected: []function.ListValidator{}, + Validators: []function.ListParameterValidator{}}, + expected: []function.ListParameterValidator{}, }, "Validators": { parameter: function.ListParameter{ - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{}, }}, - expected: []function.ListValidator{ + expected: []function.ListParameterValidator{ testvalidator.List{}, }, }, @@ -292,7 +292,7 @@ func TestListParameterListValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.ListValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/list_parameter_validator.go b/function/list_parameter_validator.go index 75682e10e..5332c42e4 100644 --- a/function/list_parameter_validator.go +++ b/function/list_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// ListValidator is a function validator for types.List parameters. -type ListValidator interface { +// ListParameterValidator is a function validator for types.List parameters. +type ListParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, ListRequest, *ListResponse) + // Validate performs the validation. + Validate(context.Context, ListParameterValidatorRequest, *ListParameterValidatorResponse) } -// ListRequest is a request for types.List schema validation. -type ListRequest struct { +// ListParameterValidatorRequest is a request for types.List schema validation. +type ListParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type ListRequest struct { Value types.List } -// ListResponse is a response to a ListRequest. -type ListResponse struct { +// ListParameterValidatorResponse is a response to a ListParameterValidatorRequest. +type ListParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/map_parameter.go b/function/map_parameter.go index 342b2e44c..626781352 100644 --- a/function/map_parameter.go +++ b/function/map_parameter.go @@ -86,10 +86,11 @@ type MapParameter struct { // Validators is a list of map validators that should be applied to the // parameter. - Validators []MapValidator + Validators []MapParameterValidator } -func (p MapParameter) MapValidators() []MapValidator { +// GetValidators returns the list of validators for the parameter. +func (p MapParameter) GetValidators() []MapParameterValidator { return p.Validators } diff --git a/function/map_parameter_test.go b/function/map_parameter_test.go index dcd351806..de8b1dc78 100644 --- a/function/map_parameter_test.go +++ b/function/map_parameter_test.go @@ -264,7 +264,7 @@ func TestMapParameterMapValidators(t *testing.T) { testCases := map[string]struct { parameter function.MapParameter - expected []function.MapValidator + expected []function.MapParameterValidator }{ "unset": { parameter: function.MapParameter{}, @@ -272,15 +272,15 @@ func TestMapParameterMapValidators(t *testing.T) { }, "Validators - empty": { parameter: function.MapParameter{ - Validators: []function.MapValidator{}}, - expected: []function.MapValidator{}, + Validators: []function.MapParameterValidator{}}, + expected: []function.MapParameterValidator{}, }, "Validators": { parameter: function.MapParameter{ - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{}, }}, - expected: []function.MapValidator{ + expected: []function.MapParameterValidator{ testvalidator.Map{}, }, }, @@ -292,7 +292,7 @@ func TestMapParameterMapValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.MapValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/map_parameter_validator.go b/function/map_parameter_validator.go index 54c10b77b..0d9ce1339 100644 --- a/function/map_parameter_validator.go +++ b/function/map_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// MapValidator is a function validator for types.Map parameters. -type MapValidator interface { +// MapParameterValidator is a function validator for types.Map parameters. +type MapParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, MapRequest, *MapResponse) + // Validate performs the validation. + Validate(context.Context, MapParameterValidatorRequest, *MapParameterValidatorResponse) } -// MapRequest is a request for types.Map schema validation. -type MapRequest struct { +// MapParameterValidatorRequest is a request for types.Map schema validation. +type MapParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type MapRequest struct { Value types.Map } -// MapResponse is a response to a MapRequest. -type MapResponse struct { +// MapParameterValidatorResponse is a response to a MapParameterValidatorRequest. +type MapParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/number_parameter.go b/function/number_parameter.go index ba7a1d5d0..1114f2354 100644 --- a/function/number_parameter.go +++ b/function/number_parameter.go @@ -69,10 +69,11 @@ type NumberParameter struct { // Validators is a list of validators that can be used to validate the // parameter. - Validators []NumberValidator + Validators []NumberParameterValidator } -func (p NumberParameter) NumberValidators() []NumberValidator { +// GetValidators returns the list of validators for the parameter. +func (p NumberParameter) GetValidators() []NumberParameterValidator { return p.Validators } diff --git a/function/number_parameter_test.go b/function/number_parameter_test.go index ec41ba93b..d9b11bbb3 100644 --- a/function/number_parameter_test.go +++ b/function/number_parameter_test.go @@ -248,7 +248,7 @@ func TestNumberParameterNumberValidators(t *testing.T) { testCases := map[string]struct { parameter function.NumberParameter - expected []function.NumberValidator + expected []function.NumberParameterValidator }{ "unset": { parameter: function.NumberParameter{}, @@ -256,15 +256,15 @@ func TestNumberParameterNumberValidators(t *testing.T) { }, "Validators - empty": { parameter: function.NumberParameter{ - Validators: []function.NumberValidator{}}, - expected: []function.NumberValidator{}, + Validators: []function.NumberParameterValidator{}}, + expected: []function.NumberParameterValidator{}, }, "Validators": { parameter: function.NumberParameter{ - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{}, }}, - expected: []function.NumberValidator{ + expected: []function.NumberParameterValidator{ testvalidator.Number{}, }, }, @@ -276,7 +276,7 @@ func TestNumberParameterNumberValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.NumberValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/number_parameter_validator.go b/function/number_parameter_validator.go index 5aa4a7d06..e726830c3 100644 --- a/function/number_parameter_validator.go +++ b/function/number_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// NumberValidator is a function validator for types.Number parameters. -type NumberValidator interface { +// NumberParameterValidator is a function validator for types.Number parameters. +type NumberParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, NumberRequest, *NumberResponse) + // Validate performs the validation. + Validate(context.Context, NumberParameterValidatorRequest, *NumberParameterValidatorResponse) } -// NumberRequest is a request for types.Number schema validation. -type NumberRequest struct { +// NumberParameterValidatorRequest is a request for types.Number schema validation. +type NumberParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type NumberRequest struct { Value types.Number } -// NumberResponse is a response to a NumberRequest. -type NumberResponse struct { +// NumberParameterValidatorResponse is a response to a NumberParameterValidatorRequest. +type NumberParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/object_parameter.go b/function/object_parameter.go index 6d10d8df5..13120c144 100644 --- a/function/object_parameter.go +++ b/function/object_parameter.go @@ -88,10 +88,11 @@ type ObjectParameter struct { // Validators is a list of object validators that should be applied to the // parameter. - Validators []ObjectValidator + Validators []ObjectParameterValidator } -func (p ObjectParameter) ObjectValidators() []ObjectValidator { +// GetValidators returns the list of validators for the parameter. +func (p ObjectParameter) GetValidators() []ObjectParameterValidator { return p.Validators } diff --git a/function/object_parameter_test.go b/function/object_parameter_test.go index 21abc0651..ef42e56b3 100644 --- a/function/object_parameter_test.go +++ b/function/object_parameter_test.go @@ -272,7 +272,7 @@ func TestObjectParameterObjectValidators(t *testing.T) { testCases := map[string]struct { parameter function.ObjectParameter - expected []function.ObjectValidator + expected []function.ObjectParameterValidator }{ "unset": { parameter: function.ObjectParameter{}, @@ -280,15 +280,15 @@ func TestObjectParameterObjectValidators(t *testing.T) { }, "Validators - empty": { parameter: function.ObjectParameter{ - Validators: []function.ObjectValidator{}}, - expected: []function.ObjectValidator{}, + Validators: []function.ObjectParameterValidator{}}, + expected: []function.ObjectParameterValidator{}, }, "Validators": { parameter: function.ObjectParameter{ - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{}, }}, - expected: []function.ObjectValidator{ + expected: []function.ObjectParameterValidator{ testvalidator.Object{}, }, }, @@ -300,7 +300,7 @@ func TestObjectParameterObjectValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.ObjectValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/object_parameter_validator.go b/function/object_parameter_validator.go index 01665b29a..f0ff13645 100644 --- a/function/object_parameter_validator.go +++ b/function/object_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// ObjectValidator is a function validator for types.Object parameters. -type ObjectValidator interface { +// ObjectParameterValidator is a function validator for types.Object parameters. +type ObjectParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, ObjectRequest, *ObjectResponse) + // Validate performs the validation. + Validate(context.Context, ObjectParameterValidatorRequest, *ObjectParameterValidatorResponse) } -// ObjectRequest is a request for types.Object schema validation. -type ObjectRequest struct { +// ObjectParameterValidatorRequest is a request for types.Object schema validation. +type ObjectParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type ObjectRequest struct { Value types.Object } -// ObjectResponse is a response to a ObjectRequest. -type ObjectResponse struct { +// ObjectParameterValidatorResponse is a response to a ObjectParameterValidatorRequest. +type ObjectParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/parameter_validation.go b/function/parameter_validation.go index 4ee49f1b4..df5957600 100644 --- a/function/parameter_validation.go +++ b/function/parameter_validation.go @@ -8,8 +8,8 @@ package function type ParameterWithBoolValidators interface { Parameter - // BoolValidators should return a list of Bool validators. - BoolValidators() []BoolValidator + // GetValidators should return a list of Bool validators. + GetValidators() []BoolParameterValidator } // ParameterWithInt64Validators is an optional interface on Parameter which @@ -17,8 +17,8 @@ type ParameterWithBoolValidators interface { type ParameterWithInt64Validators interface { Parameter - // Int64Validators should return a list of Int64 validators. - Int64Validators() []Int64Validator + // GetValidators should return a list of Int64 validators. + GetValidators() []Int64ParameterValidator } // ParameterWithFloat64Validators is an optional interface on Parameter which @@ -26,8 +26,8 @@ type ParameterWithInt64Validators interface { type ParameterWithFloat64Validators interface { Parameter - // Float64Validators should return a list of Float64 validators. - Float64Validators() []Float64Validator + // GetValidators should return a list of Float64 validators. + GetValidators() []Float64ParameterValidator } // ParameterWithDynamicValidators is an optional interface on Parameter which @@ -35,8 +35,8 @@ type ParameterWithFloat64Validators interface { type ParameterWithDynamicValidators interface { Parameter - // DynamicValidators should return a list of Dynamic validators. - DynamicValidators() []DynamicValidator + // GetValidators should return a list of Dynamic validators. + GetValidators() []DynamicParameterValidator } // ParameterWithListValidators is an optional interface on Parameter which @@ -44,8 +44,8 @@ type ParameterWithDynamicValidators interface { type ParameterWithListValidators interface { Parameter - // ListValidators should return a list of List validators. - ListValidators() []ListValidator + // GetValidators should return a list of List validators. + GetValidators() []ListParameterValidator } // ParameterWithMapValidators is an optional interface on Parameter which @@ -53,8 +53,8 @@ type ParameterWithListValidators interface { type ParameterWithMapValidators interface { Parameter - // MapValidators should return a list of Map validators. - MapValidators() []MapValidator + // GetValidators should return a list of Map validators. + GetValidators() []MapParameterValidator } // ParameterWithNumberValidators is an optional interface on Parameter which @@ -62,8 +62,8 @@ type ParameterWithMapValidators interface { type ParameterWithNumberValidators interface { Parameter - // NumberValidators should return a list of Map validators. - NumberValidators() []NumberValidator + // GetValidators should return a list of Map validators. + GetValidators() []NumberParameterValidator } // ParameterWithObjectValidators is an optional interface on Parameter which @@ -71,8 +71,8 @@ type ParameterWithNumberValidators interface { type ParameterWithObjectValidators interface { Parameter - // ObjectValidators should return a list of Object validators. - ObjectValidators() []ObjectValidator + // GetValidators should return a list of Object validators. + GetValidators() []ObjectParameterValidator } // ParameterWithSetValidators is an optional interface on Parameter which @@ -80,8 +80,8 @@ type ParameterWithObjectValidators interface { type ParameterWithSetValidators interface { Parameter - // SetValidators should return a list of Set validators. - SetValidators() []SetValidator + // GetValidators should return a list of Set validators. + GetValidators() []SetParameterValidator } // ParameterWithStringValidators is an optional interface on Parameter which @@ -89,6 +89,6 @@ type ParameterWithSetValidators interface { type ParameterWithStringValidators interface { Parameter - // StringValidators should return a list of String validators. - StringValidators() []StringValidator + // GetValidators should return a list of String validators. + GetValidators() []StringParameterValidator } diff --git a/function/set_parameter.go b/function/set_parameter.go index a69c4fb25..16a0c312b 100644 --- a/function/set_parameter.go +++ b/function/set_parameter.go @@ -86,10 +86,11 @@ type SetParameter struct { // Validators is a list of set validators that should be applied to the // parameter. - Validators []SetValidator + Validators []SetParameterValidator } -func (p SetParameter) SetValidators() []SetValidator { +// GetValidators returns the list of validators for the parameter. +func (p SetParameter) GetValidators() []SetParameterValidator { return p.Validators } diff --git a/function/set_parameter_test.go b/function/set_parameter_test.go index ab5a9de9a..1b7f43499 100644 --- a/function/set_parameter_test.go +++ b/function/set_parameter_test.go @@ -264,7 +264,7 @@ func TestSetParameterSetValidators(t *testing.T) { testCases := map[string]struct { parameter function.SetParameter - expected []function.SetValidator + expected []function.SetParameterValidator }{ "unset": { parameter: function.SetParameter{}, @@ -272,15 +272,15 @@ func TestSetParameterSetValidators(t *testing.T) { }, "Validators - empty": { parameter: function.SetParameter{ - Validators: []function.SetValidator{}}, - expected: []function.SetValidator{}, + Validators: []function.SetParameterValidator{}}, + expected: []function.SetParameterValidator{}, }, "Validators": { parameter: function.SetParameter{ - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{}, }}, - expected: []function.SetValidator{ + expected: []function.SetParameterValidator{ testvalidator.Set{}, }, }, @@ -292,7 +292,7 @@ func TestSetParameterSetValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.SetValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/set_parameter_validator.go b/function/set_parameter_validator.go index 55fad305c..9c1a12ca5 100644 --- a/function/set_parameter_validator.go +++ b/function/set_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// SetValidator is a function validator for types.Set parameters. -type SetValidator interface { +// SetParameterValidator is a function validator for types.Set parameters. +type SetParameterValidator interface { - // Validate should perform the validation. - Validate(context.Context, SetRequest, *SetResponse) + // Validate performs the validation. + Validate(context.Context, SetParameterValidatorRequest, *SetParameterValidatorResponse) } -// SetRequest is a request for types.Set schema validation. -type SetRequest struct { +// SetParameterValidatorRequest is a request for types.Set schema validation. +type SetParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type SetRequest struct { Value types.Set } -// SetResponse is a response to a SetRequest. -type SetResponse struct { +// SetParameterValidatorResponse is a response to a SetParameterValidatorRequest. +type SetParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/function/string_parameter.go b/function/string_parameter.go index 0ed17193d..6e6bfe10b 100644 --- a/function/string_parameter.go +++ b/function/string_parameter.go @@ -70,11 +70,11 @@ type StringParameter struct { // Validators is a list of string validators that should be applied to the // parameter. - Validators []StringValidator + Validators []StringParameterValidator } -// StringValidators returns the string validators for the parameter. -func (p StringParameter) StringValidators() []StringValidator { +// GetValidators returns the string validators for the parameter. +func (p StringParameter) GetValidators() []StringParameterValidator { return p.Validators } diff --git a/function/string_parameter_test.go b/function/string_parameter_test.go index 29aacaf78..772695ec4 100644 --- a/function/string_parameter_test.go +++ b/function/string_parameter_test.go @@ -248,7 +248,7 @@ func TestStringParameterStringValidators(t *testing.T) { testCases := map[string]struct { parameter function.StringParameter - expected []function.StringValidator + expected []function.StringParameterValidator }{ "unset": { parameter: function.StringParameter{}, @@ -256,15 +256,15 @@ func TestStringParameterStringValidators(t *testing.T) { }, "Validators - empty": { parameter: function.StringParameter{ - Validators: []function.StringValidator{}}, - expected: []function.StringValidator{}, + Validators: []function.StringParameterValidator{}}, + expected: []function.StringParameterValidator{}, }, "Validators": { parameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{}, }}, - expected: []function.StringValidator{ + expected: []function.StringParameterValidator{ testvalidator.String{}, }, }, @@ -276,7 +276,7 @@ func TestStringParameterStringValidators(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.parameter.StringValidators() + got := testCase.parameter.GetValidators() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/function/string_parameter_validator.go b/function/string_parameter_validator.go index 41f54b59c..9e45834b9 100644 --- a/function/string_parameter_validator.go +++ b/function/string_parameter_validator.go @@ -9,15 +9,15 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// StringValidator is a function validator for types.String parameters. -type StringValidator interface { +// StringParameterValidator is a function validator for types.String parameters. +type StringParameterValidator interface { - // ValidateString should perform the validation. - Validate(context.Context, StringRequest, *StringResponse) + // Validate performs the validation. + Validate(context.Context, StringParameterValidatorRequest, *StringParameterValidatorResponse) } -// StringRequest is a request for types.String schema validation. -type StringRequest struct { +// StringParameterValidatorRequest is a request for types.String schema validation. +type StringParameterValidatorRequest struct { // ArgumentPosition contains the position of the argument for validation. // Use this position for any response diagnostics. ArgumentPosition int64 @@ -26,8 +26,8 @@ type StringRequest struct { Value types.String } -// StringResponse is a response to a StringRequest. -type StringResponse struct { +// StringParameterValidatorResponse is a response to a StringParameterValidatorRequest. +type StringParameterValidatorResponse struct { // Error is a function error generated during validation of the Value. Error *FuncError } diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 13da0f78b..250a38c81 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -161,7 +161,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def switch parameterWithValidators := parameter.(type) { case function.ParameterWithBoolValidators: - for _, functionValidator := range parameterWithValidators.BoolValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { boolValuable, ok := attrValue.(basetypes.BoolValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -180,11 +180,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.BoolRequest{ + req := function.BoolParameterValidatorRequest{ ArgumentPosition: pos, Value: boolVal, } - resp := &function.BoolResponse{} + resp := &function.BoolParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -194,7 +194,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithDynamicValidators: - for _, functionValidator := range parameterWithValidators.DynamicValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { dynamicValuable, ok := attrValue.(basetypes.DynamicValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -213,11 +213,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.DynamicRequest{ + req := function.DynamicParameterValidatorRequest{ ArgumentPosition: pos, Value: dynamicVal, } - resp := &function.DynamicResponse{} + resp := &function.DynamicParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -227,7 +227,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithFloat64Validators: - for _, functionValidator := range parameterWithValidators.Float64Validators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { float64Valuable, ok := attrValue.(basetypes.Float64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -246,11 +246,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.Float64Request{ + req := function.Float64ParameterValidatorRequest{ ArgumentPosition: pos, Value: float64Val, } - resp := &function.Float64Response{} + resp := &function.Float64ParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -260,7 +260,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithInt64Validators: - for _, functionValidator := range parameterWithValidators.Int64Validators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { int64Valuable, ok := attrValue.(basetypes.Int64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -279,11 +279,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.Int64Request{ + req := function.Int64ParameterValidatorRequest{ ArgumentPosition: pos, Value: int64Val, } - resp := &function.Int64Response{} + resp := &function.Int64ParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -293,7 +293,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithListValidators: - for _, functionValidator := range parameterWithValidators.ListValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { listValue, ok := attrValue.(basetypes.ListValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -312,11 +312,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.ListRequest{ + req := function.ListParameterValidatorRequest{ ArgumentPosition: pos, Value: listVal, } - resp := &function.ListResponse{} + resp := &function.ListParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -326,7 +326,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithMapValidators: - for _, functionValidator := range parameterWithValidators.MapValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { mapValuable, ok := attrValue.(basetypes.MapValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -345,11 +345,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.MapRequest{ + req := function.MapParameterValidatorRequest{ ArgumentPosition: pos, Value: mapVal, } - resp := &function.MapResponse{} + resp := &function.MapParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -359,7 +359,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithNumberValidators: - for _, functionValidator := range parameterWithValidators.NumberValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { numberValuable, ok := attrValue.(basetypes.NumberValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -378,11 +378,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.NumberRequest{ + req := function.NumberParameterValidatorRequest{ ArgumentPosition: pos, Value: numberVal, } - resp := &function.NumberResponse{} + resp := &function.NumberParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -392,7 +392,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithObjectValidators: - for _, functionValidator := range parameterWithValidators.ObjectValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { objectValuable, ok := attrValue.(basetypes.ObjectValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -411,11 +411,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.ObjectRequest{ + req := function.ObjectParameterValidatorRequest{ ArgumentPosition: pos, Value: objectVal, } - resp := &function.ObjectResponse{} + resp := &function.ObjectParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -425,7 +425,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithSetValidators: - for _, functionValidator := range parameterWithValidators.SetValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { setValuable, ok := attrValue.(basetypes.SetValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -444,11 +444,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.SetRequest{ + req := function.SetParameterValidatorRequest{ ArgumentPosition: pos, Value: setVal, } - resp := &function.SetResponse{} + resp := &function.SetParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -458,7 +458,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def } } case function.ParameterWithStringValidators: - for _, functionValidator := range parameterWithValidators.StringValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { stringValuable, ok := attrValue.(basetypes.StringValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -477,11 +477,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.StringRequest{ + req := function.StringParameterValidatorRequest{ ArgumentPosition: pos, Value: stringVal, } - resp := &function.StringResponse{} + resp := &function.StringParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 30ded953d..f702221cf 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -742,9 +742,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -771,9 +771,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -801,9 +801,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -816,7 +816,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -846,9 +846,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.BoolParameter{ CustomType: testtypes.BoolType{}, - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -878,9 +878,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.BoolParameter{ CustomType: testtypes.BoolType{}, - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -908,9 +908,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.DynamicParameter{ - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(true)) @@ -937,9 +937,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.DynamicParameter{ - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -967,9 +967,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.DynamicParameter{ - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -982,7 +982,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -1012,9 +1012,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.DynamicParameter{ CustomType: testtypes.DynamicType{}, - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(true)) @@ -1042,9 +1042,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.DynamicParameter{ CustomType: testtypes.DynamicType{}, - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -1072,9 +1072,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Float64Parameter{ - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(1.0) @@ -1101,9 +1101,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Float64Parameter{ - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(2.0) @@ -1131,9 +1131,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Float64Parameter{ - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(2.0) @@ -1146,7 +1146,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(3.0) @@ -1176,9 +1176,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Float64Parameter{ CustomType: testtypes.Float64Type{}, - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(1.0) @@ -1206,9 +1206,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Float64Parameter{ CustomType: testtypes.Float64Type{}, - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(2.0) @@ -1236,9 +1236,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Int64Parameter{ - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(1) @@ -1265,9 +1265,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Int64Parameter{ - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(2) @@ -1295,9 +1295,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Int64Parameter{ - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(2) @@ -1310,7 +1310,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(3) @@ -1340,9 +1340,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Int64Parameter{ CustomType: testtypes.Int64Type{}, - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(1) @@ -1370,9 +1370,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Int64Parameter{ CustomType: testtypes.Int64Type{}, - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(2) @@ -1401,9 +1401,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.ListParameter{ ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -1431,9 +1431,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.ListParameter{ ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1463,9 +1463,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.ListParameter{ ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1479,7 +1479,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1515,9 +1515,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -1550,9 +1550,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1583,9 +1583,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.MapParameter{ ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) @@ -1614,9 +1614,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.MapParameter{ ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1647,9 +1647,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.MapParameter{ ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1663,7 +1663,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key1": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1700,9 +1700,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) @@ -1736,9 +1736,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1767,9 +1767,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.NumberParameter{ - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(1)) @@ -1796,9 +1796,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.NumberParameter{ - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(2)) @@ -1826,9 +1826,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.NumberParameter{ - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(2)) @@ -1841,7 +1841,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(3)) @@ -1871,9 +1871,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.NumberParameter{ CustomType: testtypes.NumberType{}, - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(1)) @@ -1903,9 +1903,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.NumberParameter{ CustomType: testtypes.NumberType{}, - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(2)) @@ -1937,9 +1937,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) @@ -1972,9 +1972,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2009,9 +2009,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2027,7 +2027,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute1": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2068,9 +2068,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) @@ -2108,9 +2108,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2142,9 +2142,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.SetParameter{ ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -2172,9 +2172,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.SetParameter{ ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2204,9 +2204,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.SetParameter{ ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2220,7 +2220,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2256,9 +2256,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -2291,9 +2291,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2322,9 +2322,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2351,9 +2351,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2381,9 +2381,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2396,7 +2396,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2427,9 +2427,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.StringParameter{ CustomType: testtypes.StringType{}, - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2459,9 +2459,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.StringParameter{ CustomType: testtypes.StringType{}, - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2490,9 +2490,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -2507,9 +2507,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2538,9 +2538,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -2555,9 +2555,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2585,9 +2585,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2619,9 +2619,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2657,9 +2657,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2694,9 +2694,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2734,9 +2734,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2777,9 +2777,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -2795,9 +2795,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index db6630375..3f996b12d 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -161,7 +161,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def switch parameterWithValidators := parameter.(type) { case function.ParameterWithBoolValidators: - for _, functionValidator := range parameterWithValidators.BoolValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { boolValuable, ok := attrValue.(basetypes.BoolValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -180,11 +180,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.BoolRequest{ + req := function.BoolParameterValidatorRequest{ ArgumentPosition: pos, Value: boolVal, } - resp := &function.BoolResponse{} + resp := &function.BoolParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -194,7 +194,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithDynamicValidators: - for _, functionValidator := range parameterWithValidators.DynamicValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { dynamicValuable, ok := attrValue.(basetypes.DynamicValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -213,11 +213,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.DynamicRequest{ + req := function.DynamicParameterValidatorRequest{ ArgumentPosition: pos, Value: dynamicVal, } - resp := &function.DynamicResponse{} + resp := &function.DynamicParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -227,7 +227,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithFloat64Validators: - for _, functionValidator := range parameterWithValidators.Float64Validators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { float64Valuable, ok := attrValue.(basetypes.Float64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -246,11 +246,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.Float64Request{ + req := function.Float64ParameterValidatorRequest{ ArgumentPosition: pos, Value: float64Val, } - resp := &function.Float64Response{} + resp := &function.Float64ParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -260,7 +260,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithInt64Validators: - for _, functionValidator := range parameterWithValidators.Int64Validators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { int64Valuable, ok := attrValue.(basetypes.Int64Valuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -279,11 +279,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.Int64Request{ + req := function.Int64ParameterValidatorRequest{ ArgumentPosition: pos, Value: int64Val, } - resp := &function.Int64Response{} + resp := &function.Int64ParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -293,7 +293,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithListValidators: - for _, functionValidator := range parameterWithValidators.ListValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { listValue, ok := attrValue.(basetypes.ListValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -312,11 +312,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.ListRequest{ + req := function.ListParameterValidatorRequest{ ArgumentPosition: pos, Value: listVal, } - resp := &function.ListResponse{} + resp := &function.ListParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -326,7 +326,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithMapValidators: - for _, functionValidator := range parameterWithValidators.MapValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { mapValuable, ok := attrValue.(basetypes.MapValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -345,11 +345,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.MapRequest{ + req := function.MapParameterValidatorRequest{ ArgumentPosition: pos, Value: mapVal, } - resp := &function.MapResponse{} + resp := &function.MapParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -359,7 +359,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithNumberValidators: - for _, functionValidator := range parameterWithValidators.NumberValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { numberValuable, ok := attrValue.(basetypes.NumberValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -378,11 +378,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.NumberRequest{ + req := function.NumberParameterValidatorRequest{ ArgumentPosition: pos, Value: numberVal, } - resp := &function.NumberResponse{} + resp := &function.NumberParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -392,7 +392,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithObjectValidators: - for _, functionValidator := range parameterWithValidators.ObjectValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { objectValuable, ok := attrValue.(basetypes.ObjectValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -411,11 +411,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.ObjectRequest{ + req := function.ObjectParameterValidatorRequest{ ArgumentPosition: pos, Value: objectVal, } - resp := &function.ObjectResponse{} + resp := &function.ObjectParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -425,7 +425,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithSetValidators: - for _, functionValidator := range parameterWithValidators.SetValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { setValuable, ok := attrValue.(basetypes.SetValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -444,11 +444,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.SetRequest{ + req := function.SetParameterValidatorRequest{ ArgumentPosition: pos, Value: setVal, } - resp := &function.SetResponse{} + resp := &function.SetParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -458,7 +458,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def } } case function.ParameterWithStringValidators: - for _, functionValidator := range parameterWithValidators.StringValidators() { + for _, functionValidator := range parameterWithValidators.GetValidators() { stringValuable, ok := attrValue.(basetypes.StringValuable) if !ok { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( @@ -477,11 +477,11 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, diags)) continue } - req := function.StringRequest{ + req := function.StringParameterValidatorRequest{ ArgumentPosition: pos, Value: stringVal, } - resp := &function.StringResponse{} + resp := &function.StringParameterValidatorResponse{} functionValidator.Validate(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index 4d835e389..611c759d9 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -745,9 +745,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -774,9 +774,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -804,9 +804,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -819,7 +819,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -849,9 +849,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.BoolParameter{ CustomType: testtypes.BoolType{}, - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -881,9 +881,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.BoolParameter{ CustomType: testtypes.BoolType{}, - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -911,9 +911,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.DynamicParameter{ - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(true)) @@ -940,9 +940,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.DynamicParameter{ - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -970,9 +970,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.DynamicParameter{ - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -985,7 +985,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -1015,9 +1015,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.DynamicParameter{ CustomType: testtypes.DynamicType{}, - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(true)) @@ -1045,9 +1045,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.DynamicParameter{ CustomType: testtypes.DynamicType{}, - Validators: []function.DynamicValidator{ + Validators: []function.DynamicParameterValidator{ testvalidator.Dynamic{ - ValidateMethod: func(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { + ValidateMethod: func(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { got := req.Value expected := types.DynamicValue(types.BoolValue(false)) @@ -1075,9 +1075,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Float64Parameter{ - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(1.0) @@ -1104,9 +1104,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Float64Parameter{ - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(2.0) @@ -1134,9 +1134,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Float64Parameter{ - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(2.0) @@ -1149,7 +1149,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(3.0) @@ -1179,9 +1179,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Float64Parameter{ CustomType: testtypes.Float64Type{}, - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(1.0) @@ -1209,9 +1209,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Float64Parameter{ CustomType: testtypes.Float64Type{}, - Validators: []function.Float64Validator{ + Validators: []function.Float64ParameterValidator{ testvalidator.Float64{ - ValidateMethod: func(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { + ValidateMethod: func(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { got := req.Value expected := types.Float64Value(2.0) @@ -1239,9 +1239,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Int64Parameter{ - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(1) @@ -1268,9 +1268,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Int64Parameter{ - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(2) @@ -1298,9 +1298,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.Int64Parameter{ - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(2) @@ -1313,7 +1313,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(3) @@ -1343,9 +1343,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Int64Parameter{ CustomType: testtypes.Int64Type{}, - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(1) @@ -1373,9 +1373,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.Int64Parameter{ CustomType: testtypes.Int64Type{}, - Validators: []function.Int64Validator{ + Validators: []function.Int64ParameterValidator{ testvalidator.Int64{ - ValidateMethod: func(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { + ValidateMethod: func(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { got := req.Value expected := types.Int64Value(2) @@ -1404,9 +1404,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.ListParameter{ ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -1434,9 +1434,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.ListParameter{ ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1466,9 +1466,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.ListParameter{ ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1482,7 +1482,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1518,9 +1518,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -1553,9 +1553,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.ListValidator{ + Validators: []function.ListParameterValidator{ testvalidator.List{ - ValidateMethod: func(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { + ValidateMethod: func(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { got := req.Value expected, _ := types.ListValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -1586,9 +1586,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.MapParameter{ ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) @@ -1617,9 +1617,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.MapParameter{ ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1650,9 +1650,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.MapParameter{ ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1666,7 +1666,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key1": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1703,9 +1703,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}) @@ -1739,9 +1739,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.MapValidator{ + Validators: []function.MapParameterValidator{ testvalidator.Map{ - ValidateMethod: func(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { + ValidateMethod: func(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { got := req.Value expected, _ := types.MapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true), "key2": types.BoolValue(false)}) @@ -1770,9 +1770,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.NumberParameter{ - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(1)) @@ -1799,9 +1799,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.NumberParameter{ - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(2)) @@ -1829,9 +1829,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.NumberParameter{ - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(2)) @@ -1844,7 +1844,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(3)) @@ -1874,9 +1874,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.NumberParameter{ CustomType: testtypes.NumberType{}, - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(1)) @@ -1906,9 +1906,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.NumberParameter{ CustomType: testtypes.NumberType{}, - Validators: []function.NumberValidator{ + Validators: []function.NumberParameterValidator{ testvalidator.Number{ - ValidateMethod: func(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { + ValidateMethod: func(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { got := req.Value expected := types.NumberValue(big.NewFloat(2)) @@ -1940,9 +1940,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) @@ -1975,9 +1975,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2012,9 +2012,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2030,7 +2030,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute1": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2071,9 +2071,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}) @@ -2111,9 +2111,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { AttributeTypes: map[string]attr.Type{ "boolAttribute": types.BoolType, }, - Validators: []function.ObjectValidator{ + Validators: []function.ObjectParameterValidator{ testvalidator.Object{ - ValidateMethod: func(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { + ValidateMethod: func(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { got := req.Value expected, _ := types.ObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType, "boolAttribute2": types.BoolType}, @@ -2145,9 +2145,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.SetParameter{ ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -2175,9 +2175,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.SetParameter{ ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2207,9 +2207,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.SetParameter{ ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2223,7 +2223,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2259,9 +2259,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true)}) @@ -2294,9 +2294,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, ElementType: types.BoolType, - Validators: []function.SetValidator{ + Validators: []function.SetParameterValidator{ testvalidator.Set{ - ValidateMethod: func(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { + ValidateMethod: func(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { got := req.Value expected, _ := types.SetValue(types.BoolType, []attr.Value{types.BoolValue(true), types.BoolValue(false)}) @@ -2325,9 +2325,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2354,9 +2354,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2384,9 +2384,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2399,7 +2399,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2430,9 +2430,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.StringParameter{ CustomType: testtypes.StringType{}, - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2462,9 +2462,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { Parameters: []function.Parameter{ function.StringParameter{ CustomType: testtypes.StringType{}, - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2493,9 +2493,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -2510,9 +2510,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2541,9 +2541,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(false) @@ -2558,9 +2558,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2588,9 +2588,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2622,9 +2622,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2660,9 +2660,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("false") @@ -2697,9 +2697,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2737,9 +2737,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, definition: function.Definition{ VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") @@ -2780,9 +2780,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { definition: function.Definition{ Parameters: []function.Parameter{ function.BoolParameter{ - Validators: []function.BoolValidator{ + Validators: []function.BoolParameterValidator{ testvalidator.Bool{ - ValidateMethod: func(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { + ValidateMethod: func(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { got := req.Value expected := types.BoolValue(true) @@ -2798,9 +2798,9 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, VariadicParameter: function.StringParameter{ - Validators: []function.StringValidator{ + Validators: []function.StringParameterValidator{ testvalidator.String{ - ValidateMethod: func(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { + ValidateMethod: func(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { got := req.Value expected := types.StringValue("true") diff --git a/internal/testing/testvalidator/bool.go b/internal/testing/testvalidator/bool.go index 310a15e52..2d61c1cbe 100644 --- a/internal/testing/testvalidator/bool.go +++ b/internal/testing/testvalidator/bool.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Bool = &Bool{} - _ function.BoolValidator = &Bool{} + _ validator.Bool = &Bool{} + _ function.BoolParameterValidator = &Bool{} ) // Declarative validator.Bool for unit testing. @@ -21,7 +21,7 @@ type Bool struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateBoolMethod func(context.Context, validator.BoolRequest, *validator.BoolResponse) - ValidateMethod func(context.Context, function.BoolRequest, *function.BoolResponse) + ValidateMethod func(context.Context, function.BoolParameterValidatorRequest, *function.BoolParameterValidatorResponse) } // Description satisfies the validator.Bool interface. @@ -51,8 +51,8 @@ func (v Bool) ValidateBool(ctx context.Context, req validator.BoolRequest, resp v.ValidateBoolMethod(ctx, req, resp) } -// Validate satisfies the function.BoolValidator interface. -func (v Bool) Validate(ctx context.Context, req function.BoolRequest, resp *function.BoolResponse) { +// Validate satisfies the function.BoolParameterValidator interface. +func (v Bool) Validate(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/dynamic.go b/internal/testing/testvalidator/dynamic.go index 9eb10d501..9a9d812c4 100644 --- a/internal/testing/testvalidator/dynamic.go +++ b/internal/testing/testvalidator/dynamic.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Dynamic = &Dynamic{} - _ function.DynamicValidator = &Dynamic{} + _ validator.Dynamic = &Dynamic{} + _ function.DynamicParameterValidator = &Dynamic{} ) // Declarative validator.Dynamic for unit testing. @@ -21,7 +21,7 @@ type Dynamic struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateDynamicMethod func(context.Context, validator.DynamicRequest, *validator.DynamicResponse) - ValidateMethod func(context.Context, function.DynamicRequest, *function.DynamicResponse) + ValidateMethod func(context.Context, function.DynamicParameterValidatorRequest, *function.DynamicParameterValidatorResponse) } // Description satisfies the validator.Dynamic interface. @@ -51,8 +51,8 @@ func (v Dynamic) ValidateDynamic(ctx context.Context, req validator.DynamicReque v.ValidateDynamicMethod(ctx, req, resp) } -// Validate satisfies the function.DynamicValidator interface. -func (v Dynamic) Validate(ctx context.Context, req function.DynamicRequest, resp *function.DynamicResponse) { +// Validate satisfies the function.DynamicParameterValidator interface. +func (v Dynamic) Validate(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/float64.go b/internal/testing/testvalidator/float64.go index d209e8af9..4377a8a6d 100644 --- a/internal/testing/testvalidator/float64.go +++ b/internal/testing/testvalidator/float64.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Float64 = &Float64{} - _ function.Float64Validator = &Float64{} + _ validator.Float64 = &Float64{} + _ function.Float64ParameterValidator = &Float64{} ) // Declarative validator.Float64 for unit testing. @@ -21,7 +21,7 @@ type Float64 struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateFloat64Method func(context.Context, validator.Float64Request, *validator.Float64Response) - ValidateMethod func(context.Context, function.Float64Request, *function.Float64Response) + ValidateMethod func(context.Context, function.Float64ParameterValidatorRequest, *function.Float64ParameterValidatorResponse) } // Description satisfies the validator.Float64 interface. @@ -51,8 +51,8 @@ func (v Float64) ValidateFloat64(ctx context.Context, req validator.Float64Reque v.ValidateFloat64Method(ctx, req, resp) } -// Validate satisfies the function.Float64Validator interface. -func (v Float64) Validate(ctx context.Context, req function.Float64Request, resp *function.Float64Response) { +// Validate satisfies the function.Float64ParameterValidator interface. +func (v Float64) Validate(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/int64.go b/internal/testing/testvalidator/int64.go index cbb203a0e..43a49c64f 100644 --- a/internal/testing/testvalidator/int64.go +++ b/internal/testing/testvalidator/int64.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Int64 = &Int64{} - _ function.Int64Validator = &Int64{} + _ validator.Int64 = &Int64{} + _ function.Int64ParameterValidator = &Int64{} ) // Declarative validator.Int64 for unit testing. @@ -21,7 +21,7 @@ type Int64 struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateInt64Method func(context.Context, validator.Int64Request, *validator.Int64Response) - ValidateMethod func(context.Context, function.Int64Request, *function.Int64Response) + ValidateMethod func(context.Context, function.Int64ParameterValidatorRequest, *function.Int64ParameterValidatorResponse) } // Description satisfies the validator.Int64 interface. @@ -51,8 +51,8 @@ func (v Int64) ValidateInt64(ctx context.Context, req validator.Int64Request, re v.ValidateInt64Method(ctx, req, resp) } -// Validate satisfies the function.Int64Validator interface. -func (v Int64) Validate(ctx context.Context, req function.Int64Request, resp *function.Int64Response) { +// Validate satisfies the function.Int64ParameterValidator interface. +func (v Int64) Validate(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/list.go b/internal/testing/testvalidator/list.go index b85ff04b2..2c9db35b2 100644 --- a/internal/testing/testvalidator/list.go +++ b/internal/testing/testvalidator/list.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.List = &List{} - _ function.ListValidator = &List{} + _ validator.List = &List{} + _ function.ListParameterValidator = &List{} ) // Declarative validator.List for unit testing. @@ -21,7 +21,7 @@ type List struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateListMethod func(context.Context, validator.ListRequest, *validator.ListResponse) - ValidateMethod func(context.Context, function.ListRequest, *function.ListResponse) + ValidateMethod func(context.Context, function.ListParameterValidatorRequest, *function.ListParameterValidatorResponse) } // Description satisfies the validator.List interface. @@ -51,8 +51,8 @@ func (v List) ValidateList(ctx context.Context, req validator.ListRequest, resp v.ValidateListMethod(ctx, req, resp) } -// Validate satisfies the function.ListValidator interface. -func (v List) Validate(ctx context.Context, req function.ListRequest, resp *function.ListResponse) { +// Validate satisfies the function.ListParameterValidator interface. +func (v List) Validate(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/map.go b/internal/testing/testvalidator/map.go index d3203786e..1fb56cb40 100644 --- a/internal/testing/testvalidator/map.go +++ b/internal/testing/testvalidator/map.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Map = &Map{} - _ function.MapValidator = &Map{} + _ validator.Map = &Map{} + _ function.MapParameterValidator = &Map{} ) // Declarative validator.Map for unit testing. @@ -21,7 +21,7 @@ type Map struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateMapMethod func(context.Context, validator.MapRequest, *validator.MapResponse) - ValidateMethod func(context.Context, function.MapRequest, *function.MapResponse) + ValidateMethod func(context.Context, function.MapParameterValidatorRequest, *function.MapParameterValidatorResponse) } // Description satisfies the validator.Map interface. @@ -51,8 +51,8 @@ func (v Map) ValidateMap(ctx context.Context, req validator.MapRequest, resp *va v.ValidateMapMethod(ctx, req, resp) } -// Validate satisfies the function.MapValidator interface. -func (v Map) Validate(ctx context.Context, req function.MapRequest, resp *function.MapResponse) { +// Validate satisfies the function.MapParameterValidator interface. +func (v Map) Validate(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/number.go b/internal/testing/testvalidator/number.go index c8261f710..1869f5192 100644 --- a/internal/testing/testvalidator/number.go +++ b/internal/testing/testvalidator/number.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Number = &Number{} - _ function.NumberValidator = &Number{} + _ validator.Number = &Number{} + _ function.NumberParameterValidator = &Number{} ) // Declarative validator.Number for unit testing. @@ -21,7 +21,7 @@ type Number struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateNumberMethod func(context.Context, validator.NumberRequest, *validator.NumberResponse) - ValidateMethod func(context.Context, function.NumberRequest, *function.NumberResponse) + ValidateMethod func(context.Context, function.NumberParameterValidatorRequest, *function.NumberParameterValidatorResponse) } // Description satisfies the validator.Number interface. @@ -51,8 +51,8 @@ func (v Number) ValidateNumber(ctx context.Context, req validator.NumberRequest, v.ValidateNumberMethod(ctx, req, resp) } -// Validate satisfies the function.NumberValidator interface. -func (v Number) Validate(ctx context.Context, req function.NumberRequest, resp *function.NumberResponse) { +// Validate satisfies the function.NumberParameterValidator interface. +func (v Number) Validate(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/object.go b/internal/testing/testvalidator/object.go index a55fa353b..d08e66ee9 100644 --- a/internal/testing/testvalidator/object.go +++ b/internal/testing/testvalidator/object.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Object = &Object{} - _ function.ObjectValidator = &Object{} + _ validator.Object = &Object{} + _ function.ObjectParameterValidator = &Object{} ) // Declarative validator.Object for unit testing. @@ -21,7 +21,7 @@ type Object struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateObjectMethod func(context.Context, validator.ObjectRequest, *validator.ObjectResponse) - ValidateMethod func(context.Context, function.ObjectRequest, *function.ObjectResponse) + ValidateMethod func(context.Context, function.ObjectParameterValidatorRequest, *function.ObjectParameterValidatorResponse) } // Description satisfies the validator.Object interface. @@ -51,8 +51,8 @@ func (v Object) ValidateObject(ctx context.Context, req validator.ObjectRequest, v.ValidateObjectMethod(ctx, req, resp) } -// Validate satisfies the function.ObjectValidator interface. -func (v Object) Validate(ctx context.Context, req function.ObjectRequest, resp *function.ObjectResponse) { +// Validate satisfies the function.ObjectParameterValidator interface. +func (v Object) Validate(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/set.go b/internal/testing/testvalidator/set.go index c161b8c96..8bd8f31b7 100644 --- a/internal/testing/testvalidator/set.go +++ b/internal/testing/testvalidator/set.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.Set = &Set{} - _ function.SetValidator = &Set{} + _ validator.Set = &Set{} + _ function.SetParameterValidator = &Set{} ) // Declarative validator.Set for unit testing. @@ -21,7 +21,7 @@ type Set struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateSetMethod func(context.Context, validator.SetRequest, *validator.SetResponse) - ValidateMethod func(context.Context, function.SetRequest, *function.SetResponse) + ValidateMethod func(context.Context, function.SetParameterValidatorRequest, *function.SetParameterValidatorResponse) } // Description satisfies the validator.Set interface. @@ -51,8 +51,8 @@ func (v Set) ValidateSet(ctx context.Context, req validator.SetRequest, resp *va v.ValidateSetMethod(ctx, req, resp) } -// Validate satisfies the function.SetValidator interface. -func (v Set) Validate(ctx context.Context, req function.SetRequest, resp *function.SetResponse) { +// Validate satisfies the function.SetParameterValidator interface. +func (v Set) Validate(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/string.go b/internal/testing/testvalidator/string.go index 24b5f4f68..85f2bed16 100644 --- a/internal/testing/testvalidator/string.go +++ b/internal/testing/testvalidator/string.go @@ -11,8 +11,8 @@ import ( ) var ( - _ validator.String = &String{} - _ function.StringValidator = &String{} + _ validator.String = &String{} + _ function.StringParameterValidator = &String{} ) // Declarative validator.String for unit testing. @@ -21,7 +21,7 @@ type String struct { DescriptionMethod func(context.Context) string MarkdownDescriptionMethod func(context.Context) string ValidateStringMethod func(context.Context, validator.StringRequest, *validator.StringResponse) - ValidateMethod func(context.Context, function.StringRequest, *function.StringResponse) + ValidateMethod func(context.Context, function.StringParameterValidatorRequest, *function.StringParameterValidatorResponse) } // Description satisfies the validator.String interface. @@ -51,8 +51,8 @@ func (v String) ValidateString(ctx context.Context, req validator.StringRequest, v.ValidateStringMethod(ctx, req, resp) } -// Validate satisfies the function.StringValidator interface. -func (v String) Validate(ctx context.Context, req function.StringRequest, resp *function.StringResponse) { +// Validate satisfies the function.StringParameterValidator interface. +func (v String) Validate(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { if v.ValidateMethod == nil { return } From a39677dbd9712f2b38c47cfe7cc64dc66aad928f Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Tue, 9 Apr 2024 16:12:03 -0400 Subject: [PATCH 56/62] Add website documentation for parameter-based validation --- website/docs/plugin/framework/validation.mdx | 130 ++++++++++++++++++- 1 file changed, 128 insertions(+), 2 deletions(-) diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index ad4d929cb..b3497ba76 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -5,9 +5,9 @@ description: How to validate configuration values using the provider development # Validation -The framework can return [diagnostics](/terraform/plugin/framework/diagnostics) feedback for values in provider, resource, and data source configurations. This allows you to write validations that give users feedback about required syntax, types, and acceptable values. +The framework can return [diagnostics](/terraform/plugin/framework/diagnostics) feedback for values in provider, resource, and data source configurations or [errors](/terraform/plugin/framework/functions/errors) feedback for values in function parameters. This allows you to write validations that give users feedback about required syntax, types, and acceptable values. -This page describes single attribute and type validation concepts that can be used in any data source, provider, or resource schema. Further documentation is available for other configuration validation concepts: +This page describes single attribute, parameter, and type validation concepts that can be used in any data source schema, provider schema, resource schema, or function definition. Further documentation is available for other configuration validation concepts: - [Data source validation](/terraform/plugin/framework/data-sources/validate-configuration) for multiple attributes declaratively or imperatively. - [Provider validation](/terraform/plugin/framework/providers/validate-configuration) for multiple attributes declaratively or imperatively. @@ -225,6 +225,132 @@ func Int64IsGreaterThan(expressions ...path.Expression) validator.Int64 { } ``` +## Parameter Validation + +You can introduce validation on function parameters using the generic framework-defined types such as [`types.String`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types#String). To do this, supply the `Validators` field with a list of validations, and the framework will return errors from all validators. For example: + +```go +// Typically within the function.Definition for a function. +function.StringParameter{ + // ... other Parameter configuration ... + + Validators: []function.StringParameterValidator{ + stringvalidator.LengthBetween(10, 256), + }, +}, +``` + +All validators in the slice will always be run, regardless of whether previous validators returned an error or not. + +### Creating Parameter Validators + +To create a parameter validator, you must implement at least one of the [`function` package](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function) `ParameterValidator` interfaces. For example: + +```go +// Ensure the implementation satisfies the expected interfaces +var ( + _ function.StringParameterValidator = stringLengthBetweenValidator{} +) + +type stringLengthBetweenValidator struct { + Max int + Min int +} + +// Validate runs the main validation logic of the validator, reading configuration data out of `req` and updating `resp` with diagnostics. +func (v stringLengthBetweenValidator) Validate(ctx context.Context, req validator.StringParameterValidatorRequest, resp *validator.StringParameterValidatorResponse) { + // If the value is unknown or null, there is nothing to validate. + if req.Value.IsUnknown() || req.Value.IsNull() { + return + } + + strLen := len(req.Value.ValueString()) + + if strLen < v.Min || strLen > v.Max { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + fmt.Sprintf("Invalid String Length: String length must be between %d and %d, got: %d.", v.Min, v.Max, strLen), + ) + + return + } +} +``` + +Optionally and depending on the complexity, it may be desirable to also create a helper function to instantiate the validator. For example: + +```go +func stringLengthBetween(minLength int, maxLength int) stringLengthBetweenValidator { + return stringLengthBetweenValidator{ + Max: maxLength, + Min: minLength, + } +} +``` + +A single validator type can be used as both an attribute validator and a parameter validator, as long as the validator implements the appropriate interfaces. For example: + +```go +var ( + _ validator.String = stringLengthBetweenValidator{} + _ function.StringParameterValidator = stringLengthBetweenValidator{} + +) +type stringLengthBetweenValidator struct { + Max int + Min int +} + +// Description returns a plain text description of the attribute validator's behavior, suitable for a practitioner to understand its impact. +func (v stringLengthBetweenValidator) Description(ctx context.Context) string { + return fmt.Sprintf("string length must be between %d and %d", v.Min, v.Max) +} + +// MarkdownDescription returns a markdown formatted description of the attribute validator's behavior, suitable for a practitioner to understand its impact. +func (v stringLengthBetweenValidator) MarkdownDescription(ctx context.Context) string { + return fmt.Sprintf("string length must be between `%d` and `%d`", v.Min, v.Max) +} + +// Validate runs the main validation logic of the attribute validator, reading configuration data out of `req` and updating `resp` with diagnostics. +func (v stringLengthBetweenValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { + // If the value is unknown or null, there is nothing to validate. + if req.ConfigValue.IsUnknown() || req.ConfigValue.IsNull() { + return + } + + strLen := len(req.ConfigValue.ValueString()) + + if strLen < v.Min || strLen > v.Max { + resp.Diagnostics.AddAttributeError( + req.AttributePath, + "Invalid String Length", + fmt.Sprintf("String length must be between %d and %d, got: %d.", v.Min, v.Max, strLen), + ) + + return + } +} + +// Validate runs the main validation logic of the parameter validator, reading configuration data out of `req` and updating `resp` with diagnostics. +func (v stringLengthBetweenValidator) Validate(ctx context.Context, req validator.StringParameterValidatorRequest, resp *validator.StringParameterValidatorResponse) { + // If the value is unknown or null, there is nothing to validate. + if req.Value.IsUnknown() || req.Value.IsNull() { + return + } + + strLen := len(req.Value.ValueString()) + + if strLen < v.Min || strLen > v.Max { + resp.Error = function.NewArgumentFuncError( + req.ArgumentPosition, + fmt.Sprintf("Invalid String Length: String length must be between %d and %d, got: %d.", v.Min, v.Max, strLen), + ) + + return + } +} +``` + ## Value Validation Validation of custom value types can be used for both attribute values and provider-defined function parameter values. This can be useful if you have consistent validation rules for a specific value type across multiple attributes or function parameters. From e31bd0d7c74dce13085bdbecf9cfc05a31d31370 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Tue, 9 Apr 2024 16:14:32 -0400 Subject: [PATCH 57/62] Add copyright headers --- internal/testing/testtypes/float64.go | 3 +++ internal/testing/testtypes/int64.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/internal/testing/testtypes/float64.go b/internal/testing/testtypes/float64.go index 2c92f6fdd..9de3502f3 100644 --- a/internal/testing/testtypes/float64.go +++ b/internal/testing/testtypes/float64.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package testtypes import ( diff --git a/internal/testing/testtypes/int64.go b/internal/testing/testtypes/int64.go index a4b875ea3..bb206343b 100644 --- a/internal/testing/testtypes/int64.go +++ b/internal/testing/testtypes/int64.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package testtypes import ( From ef737ac0a04c96a675508c7ada1248c97d372179 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Tue, 9 Apr 2024 16:19:52 -0400 Subject: [PATCH 58/62] Update changelog entries --- .changes/unreleased/FEATURES-20240405-183917.yaml | 6 +++--- .changes/unreleased/FEATURES-20240405-184527.yaml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.changes/unreleased/FEATURES-20240405-183917.yaml b/.changes/unreleased/FEATURES-20240405-183917.yaml index 9a939efcf..d2270bf69 100644 --- a/.changes/unreleased/FEATURES-20240405-183917.yaml +++ b/.changes/unreleased/FEATURES-20240405-183917.yaml @@ -1,7 +1,7 @@ kind: FEATURES -body: '`function`: Add `BoolValidator`, `DynamicValidator`, `Float64Validator`, `Int64Validator`, - `ListValidator`, `MapValidator`, `NumberValidator`, `ObjectValidator`, `SetValidator`, - and `StringValidator` interfaces for custom type parameter validation implementations' +body: '`function`: Add `BoolParameterValidator`, `DynamicParameterValidator`, `Float64ParameterValidator`, `Int64ParameterValidator`, + `ListParameterValidator`, `MapParameterValidator`, `NumberParameterValidator`, `ObjectParameterValidator`, `SetParameterValidator`, + and `StringParameterValidator` interfaces for custom function parameter validation implementations.' time: 2024-04-05T18:39:17.640444-04:00 custom: Issue: "971" diff --git a/.changes/unreleased/FEATURES-20240405-184527.yaml b/.changes/unreleased/FEATURES-20240405-184527.yaml index a78216a5f..187ea5b56 100644 --- a/.changes/unreleased/FEATURES-20240405-184527.yaml +++ b/.changes/unreleased/FEATURES-20240405-184527.yaml @@ -2,8 +2,8 @@ kind: FEATURES body: '`function`: Add `ParameterWithBoolValidators`, `ParameterWithInt64Validators`, `ParameterWithFloat64Validators`, `ParameterWithDynamicValidators`, `ParameterWithListValidators`, `ParameterWithMapValidators`, `ParameterWithNumberValidators`, `ParameterWithObjectValidators`, - `ParameterWithSetValidators`, and `ParameterWithStringValidators` interfaces for - custom type-specific parameter support for validation' + `ParameterWithSetValidators`, and `ParameterWithStringValidators` interfaces to enable + parameter-based validation support' time: 2024-04-05T18:45:27.979266-04:00 custom: Issue: "971" From 87b145b8e00b6f16eca0699703c021e4ecf2723c Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Thu, 11 Apr 2024 16:30:27 -0400 Subject: [PATCH 59/62] Rename `Validate()` method in parameter validator interfaces to `ValidateParameter()` --- function/bool_parameter_validator.go | 4 ++-- function/dynamic_parameter_validator.go | 4 ++-- function/float64_parameter_validator.go | 4 ++-- function/int64_parameter_validator.go | 4 ++-- function/list_parameter_validator.go | 4 ++-- function/map_parameter_validator.go | 4 ++-- function/number_parameter_validator.go | 4 ++-- function/object_parameter_validator.go | 4 ++-- function/set_parameter_validator.go | 4 ++-- function/string_parameter_validator.go | 4 ++-- internal/fromproto5/arguments_data.go | 20 ++++++++++---------- internal/fromproto6/arguments_data.go | 20 ++++++++++---------- internal/testing/testvalidator/bool.go | 4 ++-- internal/testing/testvalidator/dynamic.go | 4 ++-- internal/testing/testvalidator/float64.go | 4 ++-- internal/testing/testvalidator/int64.go | 4 ++-- internal/testing/testvalidator/list.go | 4 ++-- internal/testing/testvalidator/map.go | 4 ++-- internal/testing/testvalidator/number.go | 4 ++-- internal/testing/testvalidator/object.go | 4 ++-- internal/testing/testvalidator/set.go | 4 ++-- internal/testing/testvalidator/string.go | 4 ++-- website/docs/plugin/framework/validation.mdx | 4 ++-- 23 files changed, 62 insertions(+), 62 deletions(-) diff --git a/function/bool_parameter_validator.go b/function/bool_parameter_validator.go index 3be3c0f31..145519af2 100644 --- a/function/bool_parameter_validator.go +++ b/function/bool_parameter_validator.go @@ -12,8 +12,8 @@ import ( // BoolParameterValidator is a function validator for types.Bool parameters. type BoolParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, BoolParameterValidatorRequest, *BoolParameterValidatorResponse) + // ValidateParameterBool performs the validation. + ValidateParameterBool(context.Context, BoolParameterValidatorRequest, *BoolParameterValidatorResponse) } // BoolParameterValidatorRequest is a request for types.Bool schema validation. diff --git a/function/dynamic_parameter_validator.go b/function/dynamic_parameter_validator.go index 3e536fa8d..43c6e1a41 100644 --- a/function/dynamic_parameter_validator.go +++ b/function/dynamic_parameter_validator.go @@ -12,8 +12,8 @@ import ( // DynamicParameterValidator is a function validator for types.Dynamic parameters. type DynamicParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, DynamicParameterValidatorRequest, *DynamicParameterValidatorResponse) + // ValidateParameterDynamic performs the validation. + ValidateParameterDynamic(context.Context, DynamicParameterValidatorRequest, *DynamicParameterValidatorResponse) } // DynamicParameterValidatorRequest is a request for types.Dynamic schema validation. diff --git a/function/float64_parameter_validator.go b/function/float64_parameter_validator.go index cb8caf5f4..076128884 100644 --- a/function/float64_parameter_validator.go +++ b/function/float64_parameter_validator.go @@ -12,8 +12,8 @@ import ( // Float64ParameterValidator is a function validator for types.Float64 parameters. type Float64ParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, Float64ParameterValidatorRequest, *Float64ParameterValidatorResponse) + // ValidateParameterFloat64 performs the validation. + ValidateParameterFloat64(context.Context, Float64ParameterValidatorRequest, *Float64ParameterValidatorResponse) } // Float64ParameterValidatorRequest is a request for types.Float64 schema validation. diff --git a/function/int64_parameter_validator.go b/function/int64_parameter_validator.go index 73fc9d3d0..d938c4b93 100644 --- a/function/int64_parameter_validator.go +++ b/function/int64_parameter_validator.go @@ -12,8 +12,8 @@ import ( // Int64ParameterValidator is a function validator for types.Int64 parameters. type Int64ParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, Int64ParameterValidatorRequest, *Int64ParameterValidatorResponse) + // ValidateParameterInt64 performs the validation. + ValidateParameterInt64(context.Context, Int64ParameterValidatorRequest, *Int64ParameterValidatorResponse) } // Int64ParameterValidatorRequest is a request for types.Int64 schema validation. diff --git a/function/list_parameter_validator.go b/function/list_parameter_validator.go index 5332c42e4..3ab9a776a 100644 --- a/function/list_parameter_validator.go +++ b/function/list_parameter_validator.go @@ -12,8 +12,8 @@ import ( // ListParameterValidator is a function validator for types.List parameters. type ListParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, ListParameterValidatorRequest, *ListParameterValidatorResponse) + // ValidateParameterList performs the validation. + ValidateParameterList(context.Context, ListParameterValidatorRequest, *ListParameterValidatorResponse) } // ListParameterValidatorRequest is a request for types.List schema validation. diff --git a/function/map_parameter_validator.go b/function/map_parameter_validator.go index 0d9ce1339..97c13c5cd 100644 --- a/function/map_parameter_validator.go +++ b/function/map_parameter_validator.go @@ -12,8 +12,8 @@ import ( // MapParameterValidator is a function validator for types.Map parameters. type MapParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, MapParameterValidatorRequest, *MapParameterValidatorResponse) + // ValidateParameterMap performs the validation. + ValidateParameterMap(context.Context, MapParameterValidatorRequest, *MapParameterValidatorResponse) } // MapParameterValidatorRequest is a request for types.Map schema validation. diff --git a/function/number_parameter_validator.go b/function/number_parameter_validator.go index e726830c3..d6ea27e31 100644 --- a/function/number_parameter_validator.go +++ b/function/number_parameter_validator.go @@ -12,8 +12,8 @@ import ( // NumberParameterValidator is a function validator for types.Number parameters. type NumberParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, NumberParameterValidatorRequest, *NumberParameterValidatorResponse) + // ValidateParameterNumber performs the validation. + ValidateParameterNumber(context.Context, NumberParameterValidatorRequest, *NumberParameterValidatorResponse) } // NumberParameterValidatorRequest is a request for types.Number schema validation. diff --git a/function/object_parameter_validator.go b/function/object_parameter_validator.go index f0ff13645..b1143da20 100644 --- a/function/object_parameter_validator.go +++ b/function/object_parameter_validator.go @@ -12,8 +12,8 @@ import ( // ObjectParameterValidator is a function validator for types.Object parameters. type ObjectParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, ObjectParameterValidatorRequest, *ObjectParameterValidatorResponse) + // ValidateParameterObject ValidateParameterSet performs the validation. + ValidateParameterObject(context.Context, ObjectParameterValidatorRequest, *ObjectParameterValidatorResponse) } // ObjectParameterValidatorRequest is a request for types.Object schema validation. diff --git a/function/set_parameter_validator.go b/function/set_parameter_validator.go index 9c1a12ca5..7dcd12c9a 100644 --- a/function/set_parameter_validator.go +++ b/function/set_parameter_validator.go @@ -12,8 +12,8 @@ import ( // SetParameterValidator is a function validator for types.Set parameters. type SetParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, SetParameterValidatorRequest, *SetParameterValidatorResponse) + // ValidateParameterSet performs the validation. + ValidateParameterSet(context.Context, SetParameterValidatorRequest, *SetParameterValidatorResponse) } // SetParameterValidatorRequest is a request for types.Set schema validation. diff --git a/function/string_parameter_validator.go b/function/string_parameter_validator.go index 9e45834b9..f7b51600b 100644 --- a/function/string_parameter_validator.go +++ b/function/string_parameter_validator.go @@ -12,8 +12,8 @@ import ( // StringParameterValidator is a function validator for types.String parameters. type StringParameterValidator interface { - // Validate performs the validation. - Validate(context.Context, StringParameterValidatorRequest, *StringParameterValidatorResponse) + // ValidateParameterString performs the validation. + ValidateParameterString(context.Context, StringParameterValidatorRequest, *StringParameterValidatorResponse) } // StringParameterValidatorRequest is a request for types.String schema validation. diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index 3bc240eea..bd1ba5be7 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -185,7 +185,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: boolVal, } resp := &function.BoolParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterBool(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -218,7 +218,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: dynamicVal, } resp := &function.DynamicParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterDynamic(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -251,7 +251,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: float64Val, } resp := &function.Float64ParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterFloat64(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -284,7 +284,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: int64Val, } resp := &function.Int64ParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterInt64(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -317,7 +317,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: listVal, } resp := &function.ListParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterList(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -350,7 +350,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: mapVal, } resp := &function.MapParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterMap(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -383,7 +383,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: numberVal, } resp := &function.NumberParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterNumber(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -416,7 +416,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: objectVal, } resp := &function.ObjectParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterObject(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -449,7 +449,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: setVal, } resp := &function.SetParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterSet(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -482,7 +482,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def Value: stringVal, } resp := &function.StringParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterString(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index df55d61bc..2dc22e303 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -185,7 +185,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: boolVal, } resp := &function.BoolParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterBool(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -218,7 +218,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: dynamicVal, } resp := &function.DynamicParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterDynamic(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -251,7 +251,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: float64Val, } resp := &function.Float64ParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterFloat64(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -284,7 +284,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: int64Val, } resp := &function.Int64ParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterInt64(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -317,7 +317,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: listVal, } resp := &function.ListParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterList(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -350,7 +350,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: mapVal, } resp := &function.MapParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterMap(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -383,7 +383,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: numberVal, } resp := &function.NumberParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterNumber(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -416,7 +416,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: objectVal, } resp := &function.ObjectParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterObject(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -449,7 +449,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: setVal, } resp := &function.SetParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterSet(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, @@ -482,7 +482,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def Value: stringVal, } resp := &function.StringParameterValidatorResponse{} - functionValidator.Validate(ctx, req, resp) + functionValidator.ValidateParameterString(ctx, req, resp) if resp.Error != nil { funcError = function.ConcatFuncErrors(funcError, function.NewArgumentFuncError( pos, diff --git a/internal/testing/testvalidator/bool.go b/internal/testing/testvalidator/bool.go index 2d61c1cbe..73ef5d374 100644 --- a/internal/testing/testvalidator/bool.go +++ b/internal/testing/testvalidator/bool.go @@ -51,8 +51,8 @@ func (v Bool) ValidateBool(ctx context.Context, req validator.BoolRequest, resp v.ValidateBoolMethod(ctx, req, resp) } -// Validate satisfies the function.BoolParameterValidator interface. -func (v Bool) Validate(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { +// ValidateParameterBool satisfies the function.BoolParameterValidator interface. +func (v Bool) ValidateParameterBool(ctx context.Context, req function.BoolParameterValidatorRequest, resp *function.BoolParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/dynamic.go b/internal/testing/testvalidator/dynamic.go index 9a9d812c4..3b16920e2 100644 --- a/internal/testing/testvalidator/dynamic.go +++ b/internal/testing/testvalidator/dynamic.go @@ -51,8 +51,8 @@ func (v Dynamic) ValidateDynamic(ctx context.Context, req validator.DynamicReque v.ValidateDynamicMethod(ctx, req, resp) } -// Validate satisfies the function.DynamicParameterValidator interface. -func (v Dynamic) Validate(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { +// ValidateParameterDynamic satisfies the function.DynamicParameterValidator interface. +func (v Dynamic) ValidateParameterDynamic(ctx context.Context, req function.DynamicParameterValidatorRequest, resp *function.DynamicParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/float64.go b/internal/testing/testvalidator/float64.go index 4377a8a6d..a92b8e068 100644 --- a/internal/testing/testvalidator/float64.go +++ b/internal/testing/testvalidator/float64.go @@ -51,8 +51,8 @@ func (v Float64) ValidateFloat64(ctx context.Context, req validator.Float64Reque v.ValidateFloat64Method(ctx, req, resp) } -// Validate satisfies the function.Float64ParameterValidator interface. -func (v Float64) Validate(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { +// ValidateParameterFloat64 satisfies the function.Float64ParameterValidator interface. +func (v Float64) ValidateParameterFloat64(ctx context.Context, req function.Float64ParameterValidatorRequest, resp *function.Float64ParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/int64.go b/internal/testing/testvalidator/int64.go index 43a49c64f..56c495211 100644 --- a/internal/testing/testvalidator/int64.go +++ b/internal/testing/testvalidator/int64.go @@ -51,8 +51,8 @@ func (v Int64) ValidateInt64(ctx context.Context, req validator.Int64Request, re v.ValidateInt64Method(ctx, req, resp) } -// Validate satisfies the function.Int64ParameterValidator interface. -func (v Int64) Validate(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { +// ValidateParameterInt64 satisfies the function.Int64ParameterValidator interface. +func (v Int64) ValidateParameterInt64(ctx context.Context, req function.Int64ParameterValidatorRequest, resp *function.Int64ParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/list.go b/internal/testing/testvalidator/list.go index 2c9db35b2..fe881a83a 100644 --- a/internal/testing/testvalidator/list.go +++ b/internal/testing/testvalidator/list.go @@ -51,8 +51,8 @@ func (v List) ValidateList(ctx context.Context, req validator.ListRequest, resp v.ValidateListMethod(ctx, req, resp) } -// Validate satisfies the function.ListParameterValidator interface. -func (v List) Validate(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { +// ValidateParameterList satisfies the function.ListParameterValidator interface. +func (v List) ValidateParameterList(ctx context.Context, req function.ListParameterValidatorRequest, resp *function.ListParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/map.go b/internal/testing/testvalidator/map.go index 1fb56cb40..29f6a83bd 100644 --- a/internal/testing/testvalidator/map.go +++ b/internal/testing/testvalidator/map.go @@ -51,8 +51,8 @@ func (v Map) ValidateMap(ctx context.Context, req validator.MapRequest, resp *va v.ValidateMapMethod(ctx, req, resp) } -// Validate satisfies the function.MapParameterValidator interface. -func (v Map) Validate(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { +// ValidateParameterMap satisfies the function.MapParameterValidator interface. +func (v Map) ValidateParameterMap(ctx context.Context, req function.MapParameterValidatorRequest, resp *function.MapParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/number.go b/internal/testing/testvalidator/number.go index 1869f5192..ca510560c 100644 --- a/internal/testing/testvalidator/number.go +++ b/internal/testing/testvalidator/number.go @@ -51,8 +51,8 @@ func (v Number) ValidateNumber(ctx context.Context, req validator.NumberRequest, v.ValidateNumberMethod(ctx, req, resp) } -// Validate satisfies the function.NumberParameterValidator interface. -func (v Number) Validate(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { +// ValidateParameterNumber satisfies the function.NumberParameterValidator interface. +func (v Number) ValidateParameterNumber(ctx context.Context, req function.NumberParameterValidatorRequest, resp *function.NumberParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/object.go b/internal/testing/testvalidator/object.go index d08e66ee9..0875446d4 100644 --- a/internal/testing/testvalidator/object.go +++ b/internal/testing/testvalidator/object.go @@ -51,8 +51,8 @@ func (v Object) ValidateObject(ctx context.Context, req validator.ObjectRequest, v.ValidateObjectMethod(ctx, req, resp) } -// Validate satisfies the function.ObjectParameterValidator interface. -func (v Object) Validate(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { +// ValidateParameterObject satisfies the function.ObjectParameterValidator interface. +func (v Object) ValidateParameterObject(ctx context.Context, req function.ObjectParameterValidatorRequest, resp *function.ObjectParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/set.go b/internal/testing/testvalidator/set.go index 8bd8f31b7..fe22bc4a3 100644 --- a/internal/testing/testvalidator/set.go +++ b/internal/testing/testvalidator/set.go @@ -51,8 +51,8 @@ func (v Set) ValidateSet(ctx context.Context, req validator.SetRequest, resp *va v.ValidateSetMethod(ctx, req, resp) } -// Validate satisfies the function.SetParameterValidator interface. -func (v Set) Validate(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { +// ValidateParameterSet satisfies the function.SetParameterValidator interface. +func (v Set) ValidateParameterSet(ctx context.Context, req function.SetParameterValidatorRequest, resp *function.SetParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/internal/testing/testvalidator/string.go b/internal/testing/testvalidator/string.go index 85f2bed16..37e7a3a20 100644 --- a/internal/testing/testvalidator/string.go +++ b/internal/testing/testvalidator/string.go @@ -51,8 +51,8 @@ func (v String) ValidateString(ctx context.Context, req validator.StringRequest, v.ValidateStringMethod(ctx, req, resp) } -// Validate satisfies the function.StringParameterValidator interface. -func (v String) Validate(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { +// ValidateParameterString satisfies the function.StringParameterValidator interface. +func (v String) ValidateParameterString(ctx context.Context, req function.StringParameterValidatorRequest, resp *function.StringParameterValidatorResponse) { if v.ValidateMethod == nil { return } diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index b3497ba76..b0349fd8a 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -258,7 +258,7 @@ type stringLengthBetweenValidator struct { } // Validate runs the main validation logic of the validator, reading configuration data out of `req` and updating `resp` with diagnostics. -func (v stringLengthBetweenValidator) Validate(ctx context.Context, req validator.StringParameterValidatorRequest, resp *validator.StringParameterValidatorResponse) { +func (v stringLengthBetweenValidator) ValidateParameterString(ctx context.Context, req validator.StringParameterValidatorRequest, resp *validator.StringParameterValidatorResponse) { // If the value is unknown or null, there is nothing to validate. if req.Value.IsUnknown() || req.Value.IsNull() { return @@ -332,7 +332,7 @@ func (v stringLengthBetweenValidator) ValidateString(ctx context.Context, req va } // Validate runs the main validation logic of the parameter validator, reading configuration data out of `req` and updating `resp` with diagnostics. -func (v stringLengthBetweenValidator) Validate(ctx context.Context, req validator.StringParameterValidatorRequest, resp *validator.StringParameterValidatorResponse) { +func (v stringLengthBetweenValidator) ValidateParameterString(ctx context.Context, req validator.StringParameterValidatorRequest, resp *validator.StringParameterValidatorResponse) { // If the value is unknown or null, there is nothing to validate. if req.Value.IsUnknown() || req.Value.IsNull() { return From 851ee4633f8f2c42ba7730b3dba35fdd02835ce3 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Fri, 12 Apr 2024 16:01:33 -0400 Subject: [PATCH 60/62] Skip appending variadic values if there is an error in validation --- internal/fromproto5/arguments_data.go | 1 + internal/fromproto5/arguments_data_test.go | 109 +++++++-------------- internal/fromproto6/arguments_data.go | 2 + internal/fromproto6/arguments_data_test.go | 109 +++++++-------------- 4 files changed, 71 insertions(+), 150 deletions(-) diff --git a/internal/fromproto5/arguments_data.go b/internal/fromproto5/arguments_data.go index e92b1cfb1..fefd8a191 100644 --- a/internal/fromproto5/arguments_data.go +++ b/internal/fromproto5/arguments_data.go @@ -498,6 +498,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov5.DynamicValue, def continue } + // Skip appending argument values if parameter validation raises an error. if funcError != nil { continue } diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 16c0600ed..1833e2c6e 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -784,7 +784,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -827,7 +827,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -891,7 +891,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -950,7 +950,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -993,7 +993,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1055,7 +1055,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1114,7 +1114,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1157,7 +1157,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1219,7 +1219,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1278,7 +1278,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1321,7 +1321,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1383,7 +1383,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1445,7 +1445,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1491,7 +1491,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1564,7 +1564,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1628,7 +1628,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1675,7 +1675,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1750,7 +1750,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1809,7 +1809,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1852,7 +1852,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1916,7 +1916,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1988,7 +1988,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2041,7 +2041,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -2124,7 +2124,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2186,7 +2186,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2232,7 +2232,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -2305,7 +2305,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2364,7 +2364,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2407,7 +2407,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ @@ -2472,7 +2472,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2568,7 +2568,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: bool validator error."), function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), @@ -2631,16 +2631,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("false"), - }, - ), - }), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), ), @@ -2706,18 +2697,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("true"), - basetypes.NewStringValue("false"), - }, - ), - }), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), ), @@ -2746,18 +2726,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("false"), - basetypes.NewStringValue("false"), - }, - ), - }), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), @@ -2809,16 +2778,6 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, expected: function.NewArgumentsData([]attr.Value{ basetypes.NewBoolValue(true), - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("true"), - basetypes.NewStringValue("false"), - }, - ), }), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(2, "Error Diagnostic: string validator error."), diff --git a/internal/fromproto6/arguments_data.go b/internal/fromproto6/arguments_data.go index d2041f201..1fcf39229 100644 --- a/internal/fromproto6/arguments_data.go +++ b/internal/fromproto6/arguments_data.go @@ -498,6 +498,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def continue } + // Skip appending argument values if parameter validation raises an error. if funcError != nil { continue } @@ -525,6 +526,7 @@ func ArgumentsData(ctx context.Context, arguments []*tfprotov6.DynamicValue, def tupleTypes[i] = variadicType tupleValues[i] = val } + variadicValue, variadicValueDiags := basetypes.NewTupleValue(tupleTypes, tupleValues) funcError = function.ConcatFuncErrors(funcError, function.FuncErrorFromDiags(ctx, variadicValueDiags)) diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index 18a65b8cd..705c1d9c4 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -785,7 +785,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -828,7 +828,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -892,7 +892,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -951,7 +951,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -994,7 +994,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1056,7 +1056,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1115,7 +1115,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1158,7 +1158,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1220,7 +1220,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1279,7 +1279,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1322,7 +1322,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1384,7 +1384,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1446,7 +1446,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1492,7 +1492,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1565,7 +1565,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1629,7 +1629,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1676,7 +1676,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1751,7 +1751,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1810,7 +1810,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1853,7 +1853,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -1917,7 +1917,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -1989,7 +1989,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2042,7 +2042,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -2125,7 +2125,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2187,7 +2187,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2233,7 +2233,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ "\nError Diagnostic: error 2.", @@ -2306,7 +2306,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2365,7 +2365,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2408,7 +2408,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: error 1."+ @@ -2473,7 +2473,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.NewArgumentFuncError( 0, "Error Diagnostic: This is an error.", ), @@ -2569,7 +2569,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{}), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: bool validator error."), function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), @@ -2632,16 +2632,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("false"), - }, - ), - }), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), ), @@ -2707,18 +2698,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("true"), - basetypes.NewStringValue("false"), - }, - ), - }), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(1, "Error Diagnostic: string validator error."), ), @@ -2747,18 +2727,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, }, - expected: function.NewArgumentsData([]attr.Value{ - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("false"), - basetypes.NewStringValue("false"), - }, - ), - }), + expected: function.NewArgumentsData(nil), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), function.NewArgumentFuncError(0, "Error Diagnostic: string validator error."), @@ -2810,16 +2779,6 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, expected: function.NewArgumentsData([]attr.Value{ basetypes.NewBoolValue(true), - basetypes.NewTupleValueMust( - []attr.Type{ - basetypes.StringType{}, - basetypes.StringType{}, - }, - []attr.Value{ - basetypes.NewStringValue("true"), - basetypes.NewStringValue("false"), - }, - ), }), expectedFuncError: function.ConcatFuncErrors( function.NewArgumentFuncError(2, "Error Diagnostic: string validator error."), From b9624412d04e29067cac84a2d46364f9685a8979 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Mon, 15 Apr 2024 11:32:37 -0400 Subject: [PATCH 61/62] Update website/docs/plugin/framework/validation.mdx Co-authored-by: Austin Valle --- website/docs/plugin/framework/validation.mdx | 81 -------------------- 1 file changed, 81 deletions(-) diff --git a/website/docs/plugin/framework/validation.mdx b/website/docs/plugin/framework/validation.mdx index 22ff5bdfa..b0349fd8a 100644 --- a/website/docs/plugin/framework/validation.mdx +++ b/website/docs/plugin/framework/validation.mdx @@ -432,87 +432,6 @@ func (v computeInstanceIdentifierValue) isValid(in string) bool { } ``` -## Value Validation - -Validation of custom value types can be used for both attribute values and provider-defined function parameter values. This can be useful if you have consistent validation rules for a specific value type across multiple attributes or function parameters. - -When you implement validation on a custom value type associated with a schema attribute, you do not need to declare the same validation on the attribute, but you can supply additional validations in that manner. For example: - -```go -// Typically within the schema.Schema returned by Schema() for a provider, -// resource, or data source. -schema.StringAttribute{ - // ... other Attribute configuration ... - - // This is an example type with a corresponding custom value type - // which implements its own validation - CustomType: computeInstanceIdentifierType, - - // This is optional, example validation that is checked in addition - // to any validation performed by the custom value type - Validators: []validator.String{ - stringvalidator.LengthBetween(10, 256), - }, -} -``` - -### Defining Value Validation - -To support validation for a custom value type, you must implement [`xattr.ValidateableAttribute` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/attr/xattr#ValidateableAttribute) for attribute validation, or [`function.ValidateableParameter` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ValidateableParameter) for provider-defined function parameter validation. - -Both interfaces can be implemented if the same custom value type is used for both attributes and function parameters, for example: - -```go -// Ensure the implementation satisfies the expected interfaces -var ( - _ basetypes.StringValuable = computeInstanceIdentifierValue{} - _ xattr.ValidateableAttribute = computeInstanceIdentifierValue{} - _ function.ValidateableParameter = computeInstanceIdentifierValue{} -) - -// Other methods to implement the attr.Value interface are omitted for brevity -type computeInstanceIdentifierValue struct { - basetypes.StringValue -} - -// Implementation of the xattr.ValidateableAttribute interface -func (v computeInstanceIdentifierValue) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) { - if v.IsNull() || v.IsUnknown() { - return - } - - if !v.isValid(v.ValueString()) { - resp.Diagnostics.AddAttributeError( - req.Path, - "Compute Instance Type Validation Error", - fmt.Sprintf("Missing `instance-` prefix, got: %s", v.ValueString()), - ) - - return - } -} - -// Implementation of the function.ValidateableParameter interface -func (v computeInstanceIdentifierValue) ValidateParameter(ctx context.Context, req function.ValidateParameterRequest, resp *function.ValidateParameterResponse) { - if v.IsNull() || v.IsUnknown() { - return - } - - if !v.isValid(v.ValueString()) { - resp.Error = function.NewArgumentFuncError( - req.Position, - fmt.Sprintf("Compute Instance Type Validation Error: Missing `instance-` prefix, got: %s", v.ValueString()), - ) - - return - } -} - -func (v computeInstanceIdentifierValue) isValid(in string) bool { - return strings.HasPrefix(in, "instance-") -} -``` - ## Type Validation From 8dafce59adb96ef6434f7cf5e03125bedd3fb614 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Mon, 15 Apr 2024 11:41:45 -0400 Subject: [PATCH 62/62] Replace `create{type}Value` test helper functions with `New{Type}ValueMust` functions --- internal/fromproto5/arguments_data_test.go | 36 +++++----------------- internal/fromproto6/arguments_data_test.go | 36 +++++----------------- 2 files changed, 16 insertions(+), 56 deletions(-) diff --git a/internal/fromproto5/arguments_data_test.go b/internal/fromproto5/arguments_data_test.go index 1833e2c6e..a7948fafb 100644 --- a/internal/fromproto5/arguments_data_test.go +++ b/internal/fromproto5/arguments_data_test.go @@ -1415,7 +1415,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewListValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "list-parameter-Validators-error": { @@ -1529,7 +1529,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewListValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "list-parameter-custom-type-Validators-error": { @@ -1597,7 +1597,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + basetypes.NewMapValueMust(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), }), }, "map-parameter-Validators-error": { @@ -1714,7 +1714,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + basetypes.NewMapValueMust(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), }), }, "map-parameter-custom-type-Validators-error": { @@ -1952,7 +1952,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + basetypes.NewObjectValueMust(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), }), }, @@ -2083,7 +2083,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + basetypes.NewObjectValueMust(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), }), }, @@ -2156,7 +2156,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewSetValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "set-parameter-Validators-error": { @@ -2270,7 +2270,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewSetValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "set-parameter-custom-type-Validators-error": { @@ -2804,26 +2804,6 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { } } -func createListValue(elementType attr.Type, elements []attr.Value) basetypes.ListValue { - list, _ := basetypes.NewListValue(elementType, elements) - return list -} - -func createMapValue(elementType attr.Type, elements map[string]attr.Value) basetypes.MapValue { - mapVal, _ := basetypes.NewMapValue(elementType, elements) - return mapVal -} - -func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) basetypes.ObjectValue { - object, _ := basetypes.NewObjectValue(attributeTypes, attributes) - return object -} - -func createSetValue(elementType attr.Type, elements []attr.Value) basetypes.SetValue { - list, _ := basetypes.NewSetValue(elementType, elements) - return list -} - func createDynamicValue(value tftypes.Value) *tfprotov5.DynamicValue { dynamicVal, _ := tfprotov5.NewDynamicValue(tftypes.DynamicPseudoType, value) return &dynamicVal diff --git a/internal/fromproto6/arguments_data_test.go b/internal/fromproto6/arguments_data_test.go index 705c1d9c4..8aae7abd5 100644 --- a/internal/fromproto6/arguments_data_test.go +++ b/internal/fromproto6/arguments_data_test.go @@ -1416,7 +1416,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewListValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "list-parameter-Validators-error": { @@ -1530,7 +1530,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createListValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewListValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "list-parameter-custom-type-Validators-error": { @@ -1598,7 +1598,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + basetypes.NewMapValueMust(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), }), }, "map-parameter-Validators-error": { @@ -1715,7 +1715,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createMapValue(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), + basetypes.NewMapValueMust(types.BoolType, map[string]attr.Value{"key": types.BoolValue(true)}), }), }, "map-parameter-custom-type-Validators-error": { @@ -1953,7 +1953,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + basetypes.NewObjectValueMust(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), }), }, @@ -2084,7 +2084,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createObjectValue(map[string]attr.Type{"boolAttribute": types.BoolType}, + basetypes.NewObjectValueMust(map[string]attr.Type{"boolAttribute": types.BoolType}, map[string]attr.Value{"boolAttribute": types.BoolValue(true)}), }), }, @@ -2157,7 +2157,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewSetValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "set-parameter-Validators-error": { @@ -2271,7 +2271,7 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { }, }, expected: function.NewArgumentsData([]attr.Value{ - createSetValue(types.BoolType, []attr.Value{types.BoolValue(true)}), + basetypes.NewSetValueMust(types.BoolType, []attr.Value{types.BoolValue(true)}), }), }, "set-parameter-custom-type-Validators-error": { @@ -2805,26 +2805,6 @@ func TestArgumentsData_ParameterValidators(t *testing.T) { } } -func createListValue(elementType attr.Type, elements []attr.Value) basetypes.ListValue { - list, _ := basetypes.NewListValue(elementType, elements) - return list -} - -func createMapValue(elementType attr.Type, elements map[string]attr.Value) basetypes.MapValue { - mapVal, _ := basetypes.NewMapValue(elementType, elements) - return mapVal -} - -func createObjectValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) basetypes.ObjectValue { - object, _ := basetypes.NewObjectValue(attributeTypes, attributes) - return object -} - -func createSetValue(elementType attr.Type, elements []attr.Value) basetypes.SetValue { - list, _ := basetypes.NewSetValue(elementType, elements) - return list -} - func createDynamicValue(value tftypes.Value) *tfprotov6.DynamicValue { dynamicVal, _ := tfprotov6.NewDynamicValue(tftypes.DynamicPseudoType, value) return &dynamicVal