github.com/sylr/terraform@v0.11.12-beta1/helper/validation/validation_test.go (about) 1 package validation 2 3 import ( 4 "regexp" 5 "testing" 6 7 "github.com/hashicorp/terraform/helper/schema" 8 ) 9 10 type testCase struct { 11 val interface{} 12 f schema.SchemaValidateFunc 13 expectedErr *regexp.Regexp 14 } 15 16 func TestValidationIntBetween(t *testing.T) { 17 runTestCases(t, []testCase{ 18 { 19 val: 1, 20 f: IntBetween(1, 1), 21 }, 22 { 23 val: 1, 24 f: IntBetween(0, 2), 25 }, 26 { 27 val: 1, 28 f: IntBetween(2, 3), 29 expectedErr: regexp.MustCompile("expected [\\w]+ to be in the range \\(2 - 3\\), got 1"), 30 }, 31 { 32 val: "1", 33 f: IntBetween(2, 3), 34 expectedErr: regexp.MustCompile("expected type of [\\w]+ to be int"), 35 }, 36 }) 37 } 38 39 func TestValidationIntAtLeast(t *testing.T) { 40 runTestCases(t, []testCase{ 41 { 42 val: 1, 43 f: IntAtLeast(1), 44 }, 45 { 46 val: 1, 47 f: IntAtLeast(0), 48 }, 49 { 50 val: 1, 51 f: IntAtLeast(2), 52 expectedErr: regexp.MustCompile("expected [\\w]+ to be at least \\(2\\), got 1"), 53 }, 54 { 55 val: "1", 56 f: IntAtLeast(2), 57 expectedErr: regexp.MustCompile("expected type of [\\w]+ to be int"), 58 }, 59 }) 60 } 61 62 func TestValidationIntAtMost(t *testing.T) { 63 runTestCases(t, []testCase{ 64 { 65 val: 1, 66 f: IntAtMost(1), 67 }, 68 { 69 val: 1, 70 f: IntAtMost(2), 71 }, 72 { 73 val: 1, 74 f: IntAtMost(0), 75 expectedErr: regexp.MustCompile("expected [\\w]+ to be at most \\(0\\), got 1"), 76 }, 77 { 78 val: "1", 79 f: IntAtMost(0), 80 expectedErr: regexp.MustCompile("expected type of [\\w]+ to be int"), 81 }, 82 }) 83 } 84 85 func TestValidationStringInSlice(t *testing.T) { 86 runTestCases(t, []testCase{ 87 { 88 val: "ValidValue", 89 f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), 90 }, 91 // ignore case 92 { 93 val: "VALIDVALUE", 94 f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, true), 95 }, 96 { 97 val: "VALIDVALUE", 98 f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), 99 expectedErr: regexp.MustCompile("expected [\\w]+ to be one of \\[ValidValue AnotherValidValue\\], got VALIDVALUE"), 100 }, 101 { 102 val: "InvalidValue", 103 f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), 104 expectedErr: regexp.MustCompile("expected [\\w]+ to be one of \\[ValidValue AnotherValidValue\\], got InvalidValue"), 105 }, 106 { 107 val: 1, 108 f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), 109 expectedErr: regexp.MustCompile("expected type of [\\w]+ to be string"), 110 }, 111 }) 112 } 113 114 func TestValidationStringMatch(t *testing.T) { 115 runTestCases(t, []testCase{ 116 { 117 val: "foobar", 118 f: StringMatch(regexp.MustCompile(".*foo.*"), ""), 119 }, 120 { 121 val: "bar", 122 f: StringMatch(regexp.MustCompile(".*foo.*"), ""), 123 expectedErr: regexp.MustCompile("expected value of [\\w]+ to match regular expression " + regexp.QuoteMeta(`".*foo.*"`)), 124 }, 125 { 126 val: "bar", 127 f: StringMatch(regexp.MustCompile(".*foo.*"), "value must contain foo"), 128 expectedErr: regexp.MustCompile("invalid value for [\\w]+ \\(value must contain foo\\)"), 129 }, 130 }) 131 } 132 133 func TestValidationRegexp(t *testing.T) { 134 runTestCases(t, []testCase{ 135 { 136 val: ".*foo.*", 137 f: ValidateRegexp, 138 }, 139 { 140 val: "foo(bar", 141 f: ValidateRegexp, 142 expectedErr: regexp.MustCompile(regexp.QuoteMeta("error parsing regexp: missing closing ): `foo(bar`")), 143 }, 144 }) 145 } 146 147 func TestValidationSingleIP(t *testing.T) { 148 runTestCases(t, []testCase{ 149 { 150 val: "172.10.10.10", 151 f: SingleIP(), 152 }, 153 { 154 val: "1.1.1", 155 f: SingleIP(), 156 expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")), 157 }, 158 { 159 val: "1.1.1.0/20", 160 f: SingleIP(), 161 expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")), 162 }, 163 { 164 val: "256.1.1.1", 165 f: SingleIP(), 166 expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")), 167 }, 168 }) 169 } 170 171 func TestValidationIPRange(t *testing.T) { 172 runTestCases(t, []testCase{ 173 { 174 val: "172.10.10.10-172.10.10.12", 175 f: IPRange(), 176 }, 177 { 178 val: "172.10.10.20", 179 f: IPRange(), 180 expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP range, got:")), 181 }, 182 { 183 val: "172.10.10.20-172.10.10.12", 184 f: IPRange(), 185 expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP range, got:")), 186 }, 187 }) 188 } 189 190 func TestValidateRFC3339TimeString(t *testing.T) { 191 runTestCases(t, []testCase{ 192 { 193 val: "2018-03-01T00:00:00Z", 194 f: ValidateRFC3339TimeString, 195 }, 196 { 197 val: "2018-03-01T00:00:00-05:00", 198 f: ValidateRFC3339TimeString, 199 }, 200 { 201 val: "2018-03-01T00:00:00+05:00", 202 f: ValidateRFC3339TimeString, 203 }, 204 { 205 val: "03/01/2018", 206 f: ValidateRFC3339TimeString, 207 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 208 }, 209 { 210 val: "03-01-2018", 211 f: ValidateRFC3339TimeString, 212 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 213 }, 214 { 215 val: "2018-03-01", 216 f: ValidateRFC3339TimeString, 217 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 218 }, 219 { 220 val: "2018-03-01T", 221 f: ValidateRFC3339TimeString, 222 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 223 }, 224 { 225 val: "2018-03-01T00:00:00", 226 f: ValidateRFC3339TimeString, 227 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 228 }, 229 { 230 val: "2018-03-01T00:00:00Z05:00", 231 f: ValidateRFC3339TimeString, 232 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 233 }, 234 { 235 val: "2018-03-01T00:00:00Z-05:00", 236 f: ValidateRFC3339TimeString, 237 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 238 }, 239 }) 240 } 241 242 func TestValidateJsonString(t *testing.T) { 243 type testCases struct { 244 Value string 245 ErrCount int 246 } 247 248 invalidCases := []testCases{ 249 { 250 Value: `{0:"1"}`, 251 ErrCount: 1, 252 }, 253 { 254 Value: `{'abc':1}`, 255 ErrCount: 1, 256 }, 257 { 258 Value: `{"def":}`, 259 ErrCount: 1, 260 }, 261 { 262 Value: `{"xyz":[}}`, 263 ErrCount: 1, 264 }, 265 } 266 267 for _, tc := range invalidCases { 268 _, errors := ValidateJsonString(tc.Value, "json") 269 if len(errors) != tc.ErrCount { 270 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 271 } 272 } 273 274 validCases := []testCases{ 275 { 276 Value: ``, 277 ErrCount: 0, 278 }, 279 { 280 Value: `{}`, 281 ErrCount: 0, 282 }, 283 { 284 Value: `{"abc":["1","2"]}`, 285 ErrCount: 0, 286 }, 287 } 288 289 for _, tc := range validCases { 290 _, errors := ValidateJsonString(tc.Value, "json") 291 if len(errors) != tc.ErrCount { 292 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 293 } 294 } 295 } 296 297 func TestValidateListUniqueStrings(t *testing.T) { 298 runTestCases(t, []testCase{ 299 { 300 val: []interface{}{"foo", "bar"}, 301 f: ValidateListUniqueStrings, 302 }, 303 { 304 val: []interface{}{"foo", "bar", "foo"}, 305 f: ValidateListUniqueStrings, 306 expectedErr: regexp.MustCompile("duplicate entry - foo"), 307 }, 308 { 309 val: []interface{}{"foo", "bar", "foo", "baz", "bar"}, 310 f: ValidateListUniqueStrings, 311 expectedErr: regexp.MustCompile("duplicate entry - (?:foo|bar)"), 312 }, 313 }) 314 } 315 316 func TestValidationNoZeroValues(t *testing.T) { 317 runTestCases(t, []testCase{ 318 { 319 val: "foo", 320 f: NoZeroValues, 321 }, 322 { 323 val: 1, 324 f: NoZeroValues, 325 }, 326 { 327 val: float64(1), 328 f: NoZeroValues, 329 }, 330 { 331 val: "", 332 f: NoZeroValues, 333 expectedErr: regexp.MustCompile("must not be empty"), 334 }, 335 { 336 val: 0, 337 f: NoZeroValues, 338 expectedErr: regexp.MustCompile("must not be zero"), 339 }, 340 { 341 val: float64(0), 342 f: NoZeroValues, 343 expectedErr: regexp.MustCompile("must not be zero"), 344 }, 345 }) 346 } 347 348 func runTestCases(t *testing.T, cases []testCase) { 349 matchErr := func(errs []error, r *regexp.Regexp) bool { 350 // err must match one provided 351 for _, err := range errs { 352 if r.MatchString(err.Error()) { 353 return true 354 } 355 } 356 357 return false 358 } 359 360 for i, tc := range cases { 361 _, errs := tc.f(tc.val, "test_property") 362 363 if len(errs) == 0 && tc.expectedErr == nil { 364 continue 365 } 366 367 if len(errs) != 0 && tc.expectedErr == nil { 368 t.Fatalf("expected test case %d to produce no errors, got %v", i, errs) 369 } 370 371 if !matchErr(errs, tc.expectedErr) { 372 t.Fatalf("expected test case %d to produce error matching \"%s\", got %v", i, tc.expectedErr, errs) 373 } 374 } 375 }