diff --git a/int64validator/at_least_sum_of.go b/int64validator/at_least_sum_of.go index 1cdb040..a6b9b90 100644 --- a/int64validator/at_least_sum_of.go +++ b/int64validator/at_least_sum_of.go @@ -44,6 +44,7 @@ func (validator atLeastSumOfValidator) Validate(ctx context.Context, request tfs } var sumOfAttribs int64 + var numUnknownAttribsToSum int for _, path := range validator.attributesToSumPaths { var attribToSum types.Int64 @@ -53,9 +54,22 @@ func (validator atLeastSumOfValidator) Validate(ctx context.Context, request tfs return } + if attribToSum.Null { + continue + } + + if attribToSum.Unknown { + numUnknownAttribsToSum++ + continue + } + sumOfAttribs += attribToSum.Value } + if numUnknownAttribsToSum == len(validator.attributesToSumPaths) { + return + } + if i < sumOfAttribs { response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic( @@ -75,7 +89,7 @@ func (validator atLeastSumOfValidator) Validate(ctx context.Context, request tfs // - Is exclusively at least the sum of the given attributes. // // Null (unconfigured) and unknown (known after apply) values are skipped. -func AtLeastSumOf(attributesToSum []*tftypes.AttributePath) tfsdk.AttributeValidator { +func AtLeastSumOf(attributesToSum ...*tftypes.AttributePath) tfsdk.AttributeValidator { return atLeastSumOfValidator{ attributesToSumPaths: attributesToSum, } diff --git a/int64validator/at_least_sum_of_test.go b/int64validator/at_least_sum_of_test.go index 1f685b7..87a7360 100644 --- a/int64validator/at_least_sum_of_test.go +++ b/int64validator/at_least_sum_of_test.go @@ -86,6 +86,18 @@ func TestAtLeastSumOfValidator(t *testing.T) { "two": tftypes.NewValue(tftypes.Number, nil), }, }, + "valid integer as Int64 returns error when all attributes to sum are null": { + val: types.Int64{Value: -1}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Number, nil), + "two": tftypes.NewValue(tftypes.Number, nil), + }, + expectError: true, + }, "valid integer as Int64 greater than sum of attributes, when one summed attribute is unknown": { val: types.Int64{Value: 10}, attributesToSumPaths: []*tftypes.AttributePath{ @@ -108,6 +120,29 @@ func TestAtLeastSumOfValidator(t *testing.T) { "two": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), }, }, + "valid integer as Int64 does not return error when all attributes to sum are unknown": { + val: types.Int64{Value: -1}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), + "two": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), + }, + }, + "error when attribute to sum is not Number": { + val: types.Int64{Value: 9}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Bool, true), + "two": tftypes.NewValue(tftypes.Number, 9), + }, + expectError: true, + }, } for name, test := range tests { @@ -130,7 +165,7 @@ func TestAtLeastSumOfValidator(t *testing.T) { response := tfsdk.ValidateAttributeResponse{} - AtLeastSumOf(test.attributesToSumPaths).Validate(context.Background(), request, &response) + AtLeastSumOf(test.attributesToSumPaths...).Validate(context.Background(), request, &response) if !response.Diagnostics.HasError() && test.expectError { t.Fatal("expected error, got no error") diff --git a/int64validator/at_most_sum_of.go b/int64validator/at_most_sum_of.go index 8d41f0b..4c69703 100644 --- a/int64validator/at_most_sum_of.go +++ b/int64validator/at_most_sum_of.go @@ -44,6 +44,7 @@ func (validator atMostSumOfValidator) Validate(ctx context.Context, request tfsd } var sumOfAttribs int64 + var numUnknownAttribsToSum int for _, path := range validator.attributesToSumPaths { var attribToSum types.Int64 @@ -53,9 +54,22 @@ func (validator atMostSumOfValidator) Validate(ctx context.Context, request tfsd return } + if attribToSum.Null { + continue + } + + if attribToSum.Unknown { + numUnknownAttribsToSum++ + continue + } + sumOfAttribs += attribToSum.Value } + if numUnknownAttribsToSum == len(validator.attributesToSumPaths) { + return + } + if i > sumOfAttribs { response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic( @@ -75,7 +89,7 @@ func (validator atMostSumOfValidator) Validate(ctx context.Context, request tfsd // - Is exclusively at most the sum of the given attributes. // // Null (unconfigured) and unknown (known after apply) values are skipped. -func AtMostSumOf(attributesToSum []*tftypes.AttributePath) tfsdk.AttributeValidator { +func AtMostSumOf(attributesToSum ...*tftypes.AttributePath) tfsdk.AttributeValidator { return atMostSumOfValidator{ attributesToSumPaths: attributesToSum, } diff --git a/int64validator/at_most_sum_of_test.go b/int64validator/at_most_sum_of_test.go index 5c393bf..457889f 100644 --- a/int64validator/at_most_sum_of_test.go +++ b/int64validator/at_most_sum_of_test.go @@ -86,6 +86,18 @@ func TestAtMostSumOfValidator(t *testing.T) { "two": tftypes.NewValue(tftypes.Number, nil), }, }, + "valid integer as Int64 returns error when all attributes to sum are null": { + val: types.Int64{Value: 1}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Number, nil), + "two": tftypes.NewValue(tftypes.Number, nil), + }, + expectError: true, + }, "valid integer as Int64 less than sum of attributes, when one summed attribute is unknown": { val: types.Int64{Value: 8}, attributesToSumPaths: []*tftypes.AttributePath{ @@ -108,6 +120,29 @@ func TestAtMostSumOfValidator(t *testing.T) { "two": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), }, }, + "valid integer as Int64 does not return error when all attributes to sum are unknown": { + val: types.Int64{Value: 1}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), + "two": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), + }, + }, + "error when attribute to sum is not Number": { + val: types.Int64{Value: 9}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Bool, true), + "two": tftypes.NewValue(tftypes.Number, 9), + }, + expectError: true, + }, } for name, test := range tests { @@ -130,7 +165,7 @@ func TestAtMostSumOfValidator(t *testing.T) { response := tfsdk.ValidateAttributeResponse{} - AtMostSumOf(test.attributesToSumPaths).Validate(context.Background(), request, &response) + AtMostSumOf(test.attributesToSumPaths...).Validate(context.Background(), request, &response) if !response.Diagnostics.HasError() && test.expectError { t.Fatal("expected error, got no error") diff --git a/int64validator/equal_to_sum_of.go b/int64validator/equal_to_sum_of.go index e85d26f..2c3bc24 100644 --- a/int64validator/equal_to_sum_of.go +++ b/int64validator/equal_to_sum_of.go @@ -44,6 +44,7 @@ func (validator equalToSumOfValidator) Validate(ctx context.Context, request tfs } var sumOfAttribs int64 + var numUnknownAttribsToSum int for _, path := range validator.attributesToSumPaths { var attribToSum types.Int64 @@ -53,11 +54,23 @@ func (validator equalToSumOfValidator) Validate(ctx context.Context, request tfs return } + if attribToSum.Null { + continue + } + + if attribToSum.Unknown { + numUnknownAttribsToSum++ + continue + } + sumOfAttribs += attribToSum.Value } - if i != sumOfAttribs { + if numUnknownAttribsToSum == len(validator.attributesToSumPaths) { + return + } + if i != sumOfAttribs { response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic( request.AttributePath, validator.Description(ctx), @@ -72,10 +85,10 @@ func (validator equalToSumOfValidator) Validate(ctx context.Context, request tfs // attribute value: // // - Is a number, which can be represented by a 64-bit integer. -// - Is exclusively equal to the sum of the given attributes. +// - Is equal to the sum of the given attributes. // // Null (unconfigured) and unknown (known after apply) values are skipped. -func EqualToSumOf(attributesToSum []*tftypes.AttributePath) tfsdk.AttributeValidator { +func EqualToSumOf(attributesToSum ...*tftypes.AttributePath) tfsdk.AttributeValidator { return equalToSumOfValidator{ attributesToSumPaths: attributesToSum, } diff --git a/int64validator/equal_to_sum_of_test.go b/int64validator/equal_to_sum_of_test.go index 60a6ede..2f29178 100644 --- a/int64validator/equal_to_sum_of_test.go +++ b/int64validator/equal_to_sum_of_test.go @@ -87,6 +87,18 @@ func TestEqualToSumOfValidator(t *testing.T) { "two": tftypes.NewValue(tftypes.Number, nil), }, }, + "valid integer as Int64 returns error when all attributes to sum are null": { + val: types.Int64{Value: 1}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Number, nil), + "two": tftypes.NewValue(tftypes.Number, nil), + }, + expectError: true, + }, "valid integer as Int64 equal to sum of attributes, when one summed attribute is unknown": { val: types.Int64{Value: 8}, attributesToSumPaths: []*tftypes.AttributePath{ @@ -109,6 +121,29 @@ func TestEqualToSumOfValidator(t *testing.T) { "two": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), }, }, + "valid integer as Int64 does not return error when all attributes to sum are unknown": { + val: types.Int64{Value: 1}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), + "two": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), + }, + }, + "error when attribute to sum is not Number": { + val: types.Int64{Value: 9}, + attributesToSumPaths: []*tftypes.AttributePath{ + tftypes.NewAttributePath().WithAttributeName("one"), + tftypes.NewAttributePath().WithAttributeName("two"), + }, + requestConfigRaw: map[string]tftypes.Value{ + "one": tftypes.NewValue(tftypes.Bool, true), + "two": tftypes.NewValue(tftypes.Number, 9), + }, + expectError: true, + }, } for name, test := range tests { @@ -131,7 +166,7 @@ func TestEqualToSumOfValidator(t *testing.T) { response := tfsdk.ValidateAttributeResponse{} - EqualToSumOf(test.attributesToSumPaths).Validate(context.Background(), request, &response) + EqualToSumOf(test.attributesToSumPaths...).Validate(context.Background(), request, &response) if !response.Diagnostics.HasError() && test.expectError { t.Fatal("expected error, got no error")