Skip to content

Commit 623f39b

Browse files
committed
implement all string validator refinements
1 parent c77b5dc commit 623f39b

File tree

8 files changed

+194
-14
lines changed

8 files changed

+194
-14
lines changed

stringvalidator/length_at_most.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
1111
"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatorfuncerr"
12-
"github.com/hashicorp/terraform-plugin-framework/diag"
1312
"github.com/hashicorp/terraform-plugin-framework/function"
1413
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
1514
)
@@ -52,11 +51,11 @@ func (v lengthAtMostValidator) ValidateString(ctx context.Context, request valid
5251
}
5352

5453
if request.ConfigValue.IsUnknown() {
55-
if prefixRefn, ok := request.ConfigValue.PrefixRefinement(); ok && len(prefixRefn.PrefixValue()) > v.maxLength {
56-
response.Diagnostics.Append(diag.NewAttributeErrorDiagnostic(
54+
if refn, ok := request.ConfigValue.PrefixRefinement(); ok && len(refn.PrefixValue()) > v.maxLength {
55+
response.Diagnostics.Append(validatordiag.InvalidAttributeValueLengthDiagnostic(
5756
request.Path,
58-
"Invalid Attribute Value Length",
59-
fmt.Sprintf("Attribute %s %s, got an unknown value with a prefix of length: %d", request.Path, v.Description(ctx), len(prefixRefn.PrefixValue())),
57+
v.Description(ctx),
58+
fmt.Sprintf("unknown value with prefix of length %d", len(refn.PrefixValue())),
6059
))
6160
}
6261
return
@@ -92,10 +91,11 @@ func (v lengthAtMostValidator) ValidateParameterString(ctx context.Context, requ
9291
}
9392

9493
if request.Value.IsUnknown() {
95-
if prefixRefn, ok := request.Value.PrefixRefinement(); ok && len(prefixRefn.PrefixValue()) > v.maxLength {
96-
response.Error = function.NewArgumentFuncError(
94+
if refn, ok := request.Value.PrefixRefinement(); ok && len(refn.PrefixValue()) > v.maxLength {
95+
response.Error = validatorfuncerr.InvalidParameterValueLengthFuncError(
9796
request.ArgumentPosition,
98-
fmt.Sprintf("Invalid Parameter Value: %s, got an unknown value with a prefix of length: %d", v.Description(ctx), len(prefixRefn.PrefixValue())),
97+
v.Description(ctx),
98+
fmt.Sprintf("unknown value with prefix of length %d", len(refn.PrefixValue())),
9999
)
100100
}
101101
return

stringvalidator/length_at_most_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ func TestLengthAtMostValidator(t *testing.T) {
2929
val: types.StringUnknown(),
3030
maxLength: 1,
3131
},
32+
"unknown-prefix-valid": {
33+
val: types.StringUnknown().RefineWithPrefix("ok"),
34+
maxLength: 2,
35+
},
36+
"unknown-prefix-too-long": {
37+
val: types.StringUnknown().RefineWithPrefix("not ok"),
38+
maxLength: 5,
39+
expectError: true,
40+
},
3241
"null": {
3342
val: types.StringNull(),
3443
maxLength: 1,

stringvalidator/length_between.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,18 @@ func (v lengthBetweenValidator) ValidateString(ctx context.Context, request vali
4646
return
4747
}
4848

49-
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
49+
if request.ConfigValue.IsNull() {
50+
return
51+
}
52+
53+
if request.ConfigValue.IsUnknown() {
54+
if refn, ok := request.ConfigValue.PrefixRefinement(); ok && len(refn.PrefixValue()) > v.maxLength {
55+
response.Diagnostics.Append(validatordiag.InvalidAttributeValueLengthDiagnostic(
56+
request.Path,
57+
v.Description(ctx),
58+
fmt.Sprintf("unknown value with prefix of length %d", len(refn.PrefixValue())),
59+
))
60+
}
5061
return
5162
}
5263

@@ -75,7 +86,18 @@ func (v lengthBetweenValidator) ValidateParameterString(ctx context.Context, req
7586
return
7687
}
7788

78-
if request.Value.IsNull() || request.Value.IsUnknown() {
89+
if request.Value.IsNull() {
90+
return
91+
}
92+
93+
if request.Value.IsUnknown() {
94+
if refn, ok := request.Value.PrefixRefinement(); ok && len(refn.PrefixValue()) > v.maxLength {
95+
response.Error = validatorfuncerr.InvalidParameterValueLengthFuncError(
96+
request.ArgumentPosition,
97+
v.Description(ctx),
98+
fmt.Sprintf("unknown value with prefix of length %d", len(refn.PrefixValue())),
99+
)
100+
}
79101
return
80102
}
81103

stringvalidator/length_between_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ func TestLengthBetweenValidator(t *testing.T) {
3131
minLength: 1,
3232
maxLength: 3,
3333
},
34+
// Even if the refinement is too short, it's possible the final value could be longer, so no validation error.
35+
"unknown-prefix-valid-short": {
36+
val: types.StringUnknown().RefineWithPrefix("o"),
37+
minLength: 2,
38+
maxLength: 5,
39+
},
40+
"unknown-prefix-valid": {
41+
val: types.StringUnknown().RefineWithPrefix("ok"),
42+
minLength: 1,
43+
maxLength: 2,
44+
},
45+
"unknown-prefix-too-long": {
46+
val: types.StringUnknown().RefineWithPrefix("not ok"),
47+
minLength: 1,
48+
maxLength: 5,
49+
expectError: true,
50+
},
3451
"null": {
3552
val: types.StringNull(),
3653
minLength: 1,

stringvalidator/utf8_length_at_most.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,18 @@ func (v utf8LengthAtMostValidator) ValidateString(ctx context.Context, request v
4848
return
4949
}
5050

51-
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
51+
if request.ConfigValue.IsNull() {
52+
return
53+
}
54+
55+
if request.ConfigValue.IsUnknown() {
56+
if refn, ok := request.ConfigValue.PrefixRefinement(); ok && utf8.RuneCountInString(refn.PrefixValue()) > v.maxLength {
57+
response.Diagnostics.Append(validatordiag.InvalidAttributeValueLengthDiagnostic(
58+
request.Path,
59+
v.Description(ctx),
60+
fmt.Sprintf("unknown value with prefix UTF-8 character count of %d", utf8.RuneCountInString(refn.PrefixValue())),
61+
))
62+
}
5263
return
5364
}
5465

@@ -79,7 +90,18 @@ func (v utf8LengthAtMostValidator) ValidateParameterString(ctx context.Context,
7990
return
8091
}
8192

82-
if request.Value.IsNull() || request.Value.IsUnknown() {
93+
if request.Value.IsNull() {
94+
return
95+
}
96+
97+
if request.Value.IsUnknown() {
98+
if refn, ok := request.Value.PrefixRefinement(); ok && utf8.RuneCountInString(refn.PrefixValue()) > v.maxLength {
99+
response.Error = validatorfuncerr.InvalidParameterValueLengthFuncError(
100+
request.ArgumentPosition,
101+
v.Description(ctx),
102+
fmt.Sprintf("unknown value with prefix UTF-8 character count of %d", utf8.RuneCountInString(refn.PrefixValue())),
103+
)
104+
}
83105
return
84106
}
85107

stringvalidator/utf8_length_at_most_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,33 +37,64 @@ func TestUTF8LengthAtMostValidator(t *testing.T) {
3737
val: types.StringValue("ok"),
3838
maxLength: 3,
3939
},
40+
"valid unknown prefix single byte characters": {
41+
val: types.StringUnknown().RefineWithPrefix("ok"),
42+
maxLength: 3,
43+
},
4044
"valid mixed byte characters": {
4145
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
4246
val: types.StringValue("test⇄test"),
4347
maxLength: 9,
4448
},
49+
"valid unknown prefix mixed byte characters": {
50+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
51+
val: types.StringUnknown().RefineWithPrefix("test⇄test"),
52+
maxLength: 9,
53+
},
4554
"valid multiple byte characters": {
4655
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
4756
val: types.StringValue("⇄"),
4857
maxLength: 1,
4958
},
59+
"valid unknown prefix multiple byte characters": {
60+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
61+
val: types.StringUnknown().RefineWithPrefix("⇄"),
62+
maxLength: 1,
63+
},
5064
"invalid single byte characters": {
5165
val: types.StringValue("ok"),
5266
maxLength: 1,
5367
expectError: true,
5468
},
69+
"invalid unknown prefix single byte characters": {
70+
val: types.StringUnknown().RefineWithPrefix("ok"),
71+
maxLength: 1,
72+
expectError: true,
73+
},
5574
"invalid mixed byte characters": {
5675
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
5776
val: types.StringValue("test⇄test"),
5877
maxLength: 8,
5978
expectError: true,
6079
},
80+
"invalid unknown prefix mixed byte characters": {
81+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
82+
val: types.StringUnknown().RefineWithPrefix("test⇄test"),
83+
maxLength: 8,
84+
expectError: true,
85+
},
6186
"invalid multiple byte characters": {
6287
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
6388
val: types.StringValue("⇄⇄"),
6489
maxLength: 1,
6590
expectError: true,
6691
},
92+
"invalid unknown prefix multiple byte characters": {
93+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
94+
val: types.StringUnknown().RefineWithPrefix("⇄⇄"),
95+
maxLength: 1,
96+
expectError: true,
97+
},
6798
"invalid validator usage - maxLength < 0": {
6899
val: types.StringValue("ok"),
69100
maxLength: -1,

stringvalidator/utf8_length_between.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,18 @@ func (v utf8LengthBetweenValidator) ValidateString(ctx context.Context, request
4949
return
5050
}
5151

52-
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
52+
if request.ConfigValue.IsNull() {
53+
return
54+
}
55+
56+
if request.ConfigValue.IsUnknown() {
57+
if refn, ok := request.ConfigValue.PrefixRefinement(); ok && utf8.RuneCountInString(refn.PrefixValue()) > v.maxLength {
58+
response.Diagnostics.Append(validatordiag.InvalidAttributeValueLengthDiagnostic(
59+
request.Path,
60+
v.Description(ctx),
61+
fmt.Sprintf("unknown value with prefix UTF-8 character count of %d", utf8.RuneCountInString(refn.PrefixValue())),
62+
))
63+
}
5364
return
5465
}
5566

@@ -80,7 +91,18 @@ func (v utf8LengthBetweenValidator) ValidateParameterString(ctx context.Context,
8091
return
8192
}
8293

83-
if request.Value.IsNull() || request.Value.IsUnknown() {
94+
if request.Value.IsNull() {
95+
return
96+
}
97+
98+
if request.Value.IsUnknown() {
99+
if refn, ok := request.Value.PrefixRefinement(); ok && utf8.RuneCountInString(refn.PrefixValue()) > v.maxLength {
100+
response.Error = validatorfuncerr.InvalidParameterValueLengthFuncError(
101+
request.ArgumentPosition,
102+
v.Description(ctx),
103+
fmt.Sprintf("unknown value with prefix UTF-8 character count of %d", utf8.RuneCountInString(refn.PrefixValue())),
104+
)
105+
}
84106
return
85107
}
86108

stringvalidator/utf8_length_between_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,38 +41,95 @@ func TestUTF8LengthBetweenValidator(t *testing.T) {
4141
minLength: 2,
4242
maxLength: 3,
4343
},
44+
"valid unknown prefix single byte characters": {
45+
val: types.StringUnknown().RefineWithPrefix("ok"),
46+
minLength: 2,
47+
maxLength: 3,
48+
},
49+
// Even if the refinement is too short, it's possible the final value could be longer, so no validation error.
50+
"valid unknown prefix single byte characters - too short": {
51+
val: types.StringUnknown().RefineWithPrefix("ok"),
52+
minLength: 5,
53+
maxLength: 6,
54+
},
4455
"valid mixed byte characters": {
4556
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
4657
val: types.StringValue("test⇄test"),
4758
minLength: 8,
4859
maxLength: 9,
4960
},
61+
"valid unknown prefix mixed byte characters": {
62+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
63+
val: types.StringUnknown().RefineWithPrefix("test⇄test"),
64+
minLength: 8,
65+
maxLength: 9,
66+
},
67+
// Even if the refinement is too short, it's possible the final value could be longer, so no validation error.
68+
"valid unknown prefix mixed byte characters - too short": {
69+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
70+
val: types.StringUnknown().RefineWithPrefix("test⇄test"),
71+
minLength: 12,
72+
maxLength: 14,
73+
},
5074
"valid multiple byte characters": {
5175
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
5276
val: types.StringValue("⇄"),
5377
minLength: 1,
5478
maxLength: 1,
5579
},
80+
"valid unknown prefix multiple byte characters": {
81+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
82+
val: types.StringUnknown().RefineWithPrefix("⇄"),
83+
minLength: 1,
84+
maxLength: 1,
85+
},
86+
// Even if the refinement is too short, it's possible the final value could be longer, so no validation error.
87+
"valid unknown prefix multiple byte characters - too short": {
88+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
89+
val: types.StringUnknown().RefineWithPrefix("⇄"),
90+
minLength: 3,
91+
maxLength: 4,
92+
},
5693
"invalid single byte characters": {
5794
val: types.StringValue("ok"),
5895
minLength: 1,
5996
maxLength: 1,
6097
expectError: true,
6198
},
99+
"invalid unknown prefix single byte characters": {
100+
val: types.StringUnknown().RefineWithPrefix("ok"),
101+
minLength: 1,
102+
maxLength: 1,
103+
expectError: true,
104+
},
62105
"invalid mixed byte characters": {
63106
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
64107
val: types.StringValue("test⇄test"),
65108
minLength: 8,
66109
maxLength: 8,
67110
expectError: true,
68111
},
112+
"invalid unknown prefix mixed byte characters": {
113+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
114+
val: types.StringUnknown().RefineWithPrefix("test⇄test"),
115+
minLength: 8,
116+
maxLength: 8,
117+
expectError: true,
118+
},
69119
"invalid multiple byte characters": {
70120
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
71121
val: types.StringValue("⇄⇄"),
72122
minLength: 1,
73123
maxLength: 1,
74124
expectError: true,
75125
},
126+
"invalid unknown prefix multiple byte characters": {
127+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
128+
val: types.StringUnknown().RefineWithPrefix("⇄⇄"),
129+
minLength: 1,
130+
maxLength: 1,
131+
expectError: true,
132+
},
76133
"invalid validator usage - minLength < 0": {
77134
val: types.StringValue("ok"),
78135
minLength: -1,

0 commit comments

Comments
 (0)