github.com/hashicorp/terraform-plugin-sdk@v1.17.2/helper/validation/strings.go (about) 1 package validation 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "regexp" 7 "strings" 8 9 "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 10 "github.com/hashicorp/terraform-plugin-sdk/helper/structure" 11 ) 12 13 // StringIsNotEmpty is a ValidateFunc that ensures a string is not empty 14 func StringIsNotEmpty(i interface{}, k string) ([]string, []error) { 15 v, ok := i.(string) 16 if !ok { 17 return nil, []error{fmt.Errorf("expected type of %q to be string", k)} 18 } 19 20 if v == "" { 21 return nil, []error{fmt.Errorf("expected %q to not be an empty string, got %v", k, i)} 22 } 23 24 return nil, nil 25 } 26 27 // StringIsNotWhiteSpace is a ValidateFunc that ensures a string is not empty or consisting entirely of whitespace characters 28 func StringIsNotWhiteSpace(i interface{}, k string) ([]string, []error) { 29 v, ok := i.(string) 30 if !ok { 31 return nil, []error{fmt.Errorf("expected type of %q to be string", k)} 32 } 33 34 if strings.TrimSpace(v) == "" { 35 return nil, []error{fmt.Errorf("expected %q to not be an empty string or whitespace", k)} 36 } 37 38 return nil, nil 39 } 40 41 // StringIsEmpty is a ValidateFunc that ensures a string has no characters 42 func StringIsEmpty(i interface{}, k string) ([]string, []error) { 43 v, ok := i.(string) 44 if !ok { 45 return nil, []error{fmt.Errorf("expected type of %q to be string", k)} 46 } 47 48 if v != "" { 49 return nil, []error{fmt.Errorf("expected %q to be an empty string: got %v", k, v)} 50 } 51 52 return nil, nil 53 } 54 55 // StringIsWhiteSpace is a ValidateFunc that ensures a string is composed of entirely whitespace 56 func StringIsWhiteSpace(i interface{}, k string) ([]string, []error) { 57 v, ok := i.(string) 58 if !ok { 59 return nil, []error{fmt.Errorf("expected type of %q to be string", k)} 60 } 61 62 if strings.TrimSpace(v) != "" { 63 return nil, []error{fmt.Errorf("expected %q to be an empty string or whitespace: got %v", k, v)} 64 } 65 66 return nil, nil 67 } 68 69 // StringLenBetween returns a SchemaValidateFunc which tests if the provided value 70 // is of type string and has length between min and max (inclusive) 71 func StringLenBetween(min, max int) schema.SchemaValidateFunc { 72 return func(i interface{}, k string) (warnings []string, errors []error) { 73 v, ok := i.(string) 74 if !ok { 75 errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) 76 return warnings, errors 77 } 78 79 if len(v) < min || len(v) > max { 80 errors = append(errors, fmt.Errorf("expected length of %s to be in the range (%d - %d), got %s", k, min, max, v)) 81 } 82 83 return warnings, errors 84 } 85 } 86 87 // StringMatch returns a SchemaValidateFunc which tests if the provided value 88 // matches a given regexp. Optionally an error message can be provided to 89 // return something friendlier than "must match some globby regexp". 90 func StringMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc { 91 return func(i interface{}, k string) ([]string, []error) { 92 v, ok := i.(string) 93 if !ok { 94 return nil, []error{fmt.Errorf("expected type of %s to be string", k)} 95 } 96 97 if ok := r.MatchString(v); !ok { 98 if message != "" { 99 return nil, []error{fmt.Errorf("invalid value for %s (%s)", k, message)} 100 101 } 102 return nil, []error{fmt.Errorf("expected value of %s to match regular expression %q, got %v", k, r, i)} 103 } 104 return nil, nil 105 } 106 } 107 108 // StringDoesNotMatch returns a SchemaValidateFunc which tests if the provided value 109 // does not match a given regexp. Optionally an error message can be provided to 110 // return something friendlier than "must not match some globby regexp". 111 func StringDoesNotMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc { 112 return func(i interface{}, k string) ([]string, []error) { 113 v, ok := i.(string) 114 if !ok { 115 return nil, []error{fmt.Errorf("expected type of %s to be string", k)} 116 } 117 118 if ok := r.MatchString(v); ok { 119 if message != "" { 120 return nil, []error{fmt.Errorf("invalid value for %s (%s)", k, message)} 121 122 } 123 return nil, []error{fmt.Errorf("expected value of %s to not match regular expression %q, got %v", k, r, i)} 124 } 125 return nil, nil 126 } 127 } 128 129 // StringInSlice returns a SchemaValidateFunc which tests if the provided value 130 // is of type string and matches the value of an element in the valid slice 131 // will test with in lower case if ignoreCase is true 132 func StringInSlice(valid []string, ignoreCase bool) schema.SchemaValidateFunc { 133 return func(i interface{}, k string) (warnings []string, errors []error) { 134 v, ok := i.(string) 135 if !ok { 136 errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) 137 return warnings, errors 138 } 139 140 for _, str := range valid { 141 if v == str || (ignoreCase && strings.ToLower(v) == strings.ToLower(str)) { 142 return warnings, errors 143 } 144 } 145 146 errors = append(errors, fmt.Errorf("expected %s to be one of %v, got %s", k, valid, v)) 147 return warnings, errors 148 } 149 } 150 151 // StringNotInSlice returns a SchemaValidateFunc which tests if the provided value 152 // is of type string and does not match the value of any element in the invalid slice 153 // will test with in lower case if ignoreCase is true 154 func StringNotInSlice(invalid []string, ignoreCase bool) schema.SchemaValidateFunc { 155 return func(i interface{}, k string) (warnings []string, errors []error) { 156 v, ok := i.(string) 157 if !ok { 158 errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) 159 return warnings, errors 160 } 161 162 for _, str := range invalid { 163 if v == str || (ignoreCase && strings.ToLower(v) == strings.ToLower(str)) { 164 errors = append(errors, fmt.Errorf("expected %s to not be any of %v, got %s", k, invalid, v)) 165 return warnings, errors 166 } 167 } 168 169 return warnings, errors 170 } 171 } 172 173 // StringDoesNotContainAny returns a SchemaValidateFunc which validates that the 174 // provided value does not contain any of the specified Unicode code points in chars. 175 func StringDoesNotContainAny(chars string) schema.SchemaValidateFunc { 176 return func(i interface{}, k string) (warnings []string, errors []error) { 177 v, ok := i.(string) 178 if !ok { 179 errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) 180 return warnings, errors 181 } 182 183 if strings.ContainsAny(v, chars) { 184 errors = append(errors, fmt.Errorf("expected value of %s to not contain any of %q, got %v", k, chars, i)) 185 return warnings, errors 186 } 187 188 return warnings, errors 189 } 190 } 191 192 // StringIsBase64 is a ValidateFunc that ensures a string can be parsed as Base64 193 func StringIsBase64(i interface{}, k string) (warnings []string, errors []error) { 194 // Empty string is not allowed 195 if warnings, errors = StringIsNotEmpty(i, k); len(errors) > 0 { 196 return 197 } 198 199 // NoEmptyStrings checks it is a string 200 v, _ := i.(string) 201 202 if _, err := base64.StdEncoding.DecodeString(v); err != nil { 203 errors = append(errors, fmt.Errorf("expected %q to be a base64 string, got %v", k, v)) 204 } 205 206 return warnings, errors 207 } 208 209 // ValidateJsonString is a SchemaValidateFunc which tests to make sure the 210 // supplied string is valid JSON. 211 // 212 // Deprecated: use StringIsJSON instead 213 func ValidateJsonString(i interface{}, k string) (warnings []string, errors []error) { 214 return StringIsJSON(i, k) 215 } 216 217 // StringIsJSON is a SchemaValidateFunc which tests to make sure the supplied string is valid JSON. 218 func StringIsJSON(i interface{}, k string) (warnings []string, errors []error) { 219 v, ok := i.(string) 220 if !ok { 221 errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) 222 return warnings, errors 223 } 224 225 if _, err := structure.NormalizeJsonString(v); err != nil { 226 errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) 227 } 228 229 return warnings, errors 230 } 231 232 // ValidateRegexp returns a SchemaValidateFunc which tests to make sure the 233 // supplied string is a valid regular expression. 234 // 235 // Deprecated: use StringIsValidRegExp instead 236 func ValidateRegexp(i interface{}, k string) (warnings []string, errors []error) { 237 return StringIsValidRegExp(i, k) 238 } 239 240 // StringIsValidRegExp returns a SchemaValidateFunc which tests to make sure the supplied string is a valid regular expression. 241 func StringIsValidRegExp(i interface{}, k string) (warnings []string, errors []error) { 242 v, ok := i.(string) 243 if !ok { 244 errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) 245 return warnings, errors 246 } 247 248 if _, err := regexp.Compile(v); err != nil { 249 errors = append(errors, fmt.Errorf("%q: %s", k, err)) 250 } 251 252 return warnings, errors 253 }