github.com/scottwinkler/terraform@v0.11.6-0.20180329211809-05143987aea8/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 TestValidateRFC3339TimeString(t *testing.T) { 148 runTestCases(t, []testCase{ 149 { 150 val: "2018-03-01T00:00:00Z", 151 f: ValidateRFC3339TimeString, 152 }, 153 { 154 val: "2018-03-01T00:00:00-05:00", 155 f: ValidateRFC3339TimeString, 156 }, 157 { 158 val: "2018-03-01T00:00:00+05:00", 159 f: ValidateRFC3339TimeString, 160 }, 161 { 162 val: "03/01/2018", 163 f: ValidateRFC3339TimeString, 164 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 165 }, 166 { 167 val: "03-01-2018", 168 f: ValidateRFC3339TimeString, 169 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 170 }, 171 { 172 val: "2018-03-01", 173 f: ValidateRFC3339TimeString, 174 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 175 }, 176 { 177 val: "2018-03-01T", 178 f: ValidateRFC3339TimeString, 179 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 180 }, 181 { 182 val: "2018-03-01T00:00:00", 183 f: ValidateRFC3339TimeString, 184 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 185 }, 186 { 187 val: "2018-03-01T00:00:00Z05:00", 188 f: ValidateRFC3339TimeString, 189 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 190 }, 191 { 192 val: "2018-03-01T00:00:00Z-05:00", 193 f: ValidateRFC3339TimeString, 194 expectedErr: regexp.MustCompile(regexp.QuoteMeta(`invalid RFC3339 timestamp`)), 195 }, 196 }) 197 } 198 199 func TestValidateJsonString(t *testing.T) { 200 type testCases struct { 201 Value string 202 ErrCount int 203 } 204 205 invalidCases := []testCases{ 206 { 207 Value: `{0:"1"}`, 208 ErrCount: 1, 209 }, 210 { 211 Value: `{'abc':1}`, 212 ErrCount: 1, 213 }, 214 { 215 Value: `{"def":}`, 216 ErrCount: 1, 217 }, 218 { 219 Value: `{"xyz":[}}`, 220 ErrCount: 1, 221 }, 222 } 223 224 for _, tc := range invalidCases { 225 _, errors := ValidateJsonString(tc.Value, "json") 226 if len(errors) != tc.ErrCount { 227 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 228 } 229 } 230 231 validCases := []testCases{ 232 { 233 Value: ``, 234 ErrCount: 0, 235 }, 236 { 237 Value: `{}`, 238 ErrCount: 0, 239 }, 240 { 241 Value: `{"abc":["1","2"]}`, 242 ErrCount: 0, 243 }, 244 } 245 246 for _, tc := range validCases { 247 _, errors := ValidateJsonString(tc.Value, "json") 248 if len(errors) != tc.ErrCount { 249 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 250 } 251 } 252 } 253 254 func TestValidateListUniqueStrings(t *testing.T) { 255 runTestCases(t, []testCase{ 256 { 257 val: []interface{}{"foo", "bar"}, 258 f: ValidateListUniqueStrings, 259 }, 260 { 261 val: []interface{}{"foo", "bar", "foo"}, 262 f: ValidateListUniqueStrings, 263 expectedErr: regexp.MustCompile("duplicate entry - foo"), 264 }, 265 { 266 val: []interface{}{"foo", "bar", "foo", "baz", "bar"}, 267 f: ValidateListUniqueStrings, 268 expectedErr: regexp.MustCompile("duplicate entry - (?:foo|bar)"), 269 }, 270 }) 271 } 272 273 func TestValidationNoZeroValues(t *testing.T) { 274 runTestCases(t, []testCase{ 275 { 276 val: "foo", 277 f: NoZeroValues, 278 }, 279 { 280 val: 1, 281 f: NoZeroValues, 282 }, 283 { 284 val: float64(1), 285 f: NoZeroValues, 286 }, 287 { 288 val: "", 289 f: NoZeroValues, 290 expectedErr: regexp.MustCompile("must not be empty"), 291 }, 292 { 293 val: 0, 294 f: NoZeroValues, 295 expectedErr: regexp.MustCompile("must not be zero"), 296 }, 297 { 298 val: float64(0), 299 f: NoZeroValues, 300 expectedErr: regexp.MustCompile("must not be zero"), 301 }, 302 }) 303 } 304 305 func runTestCases(t *testing.T, cases []testCase) { 306 matchErr := func(errs []error, r *regexp.Regexp) bool { 307 // err must match one provided 308 for _, err := range errs { 309 if r.MatchString(err.Error()) { 310 return true 311 } 312 } 313 314 return false 315 } 316 317 for i, tc := range cases { 318 _, errs := tc.f(tc.val, "test_property") 319 320 if len(errs) == 0 && tc.expectedErr == nil { 321 continue 322 } 323 324 if len(errs) != 0 && tc.expectedErr == nil { 325 t.Fatalf("expected test case %d to produce no errors, got %v", i, errs) 326 } 327 328 if !matchErr(errs, tc.expectedErr) { 329 t.Fatalf("expected test case %d to produce error matching \"%s\", got %v", i, tc.expectedErr, errs) 330 } 331 } 332 }