From 8abec085ec0af0319d561e5328fd0ac285c2244f Mon Sep 17 00:00:00 2001 From: Peter McAtominey Date: Wed, 10 Aug 2016 13:14:25 +0100 Subject: [PATCH] helper: create validation package to provide common validation functions --- helper/validation/validation.go | 49 +++++++++++++++ helper/validation/validation_test.go | 91 ++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 helper/validation/validation.go create mode 100644 helper/validation/validation_test.go diff --git a/helper/validation/validation.go b/helper/validation/validation.go new file mode 100644 index 000000000..484f7d7da --- /dev/null +++ b/helper/validation/validation.go @@ -0,0 +1,49 @@ +package validation + +import ( + "fmt" + "strings" + + "github.com/hashicorp/terraform/helper/schema" +) + +// IntBetween returns a SchemaValidateFunc which tests if the provided value +// is of type int and is between min and max (inclusive) +func IntBetween(min, max int) schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(int) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be int", k)) + return + } + + if v < min || v > max { + es = append(es, fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)) + return + } + + return + } +} + +// StringInSlice returns a SchemaValidateFunc which tests if the provided value +// is of type string and matches the value of an element in the valid slice +// will test with in lower case if ignoreCase is true +func StringInSlice(valid []string, ignoreCase bool) schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + for _, str := range valid { + if v == str || (ignoreCase && strings.ToLower(v) == strings.ToLower(str)) { + return + } + } + + es = append(es, fmt.Errorf("expected %s to be one of %v, got %s", k, valid, v)) + return + } +} diff --git a/helper/validation/validation_test.go b/helper/validation/validation_test.go new file mode 100644 index 000000000..b6ff5e5d9 --- /dev/null +++ b/helper/validation/validation_test.go @@ -0,0 +1,91 @@ +package validation + +import ( + "regexp" + "testing" + + "github.com/hashicorp/terraform/helper/schema" +) + +type testCase struct { + val interface{} + f schema.SchemaValidateFunc + expectedErr *regexp.Regexp +} + +func TestValidationIntBetween(t *testing.T) { + runTestCases(t, []testCase{ + { + val: 1, + f: IntBetween(1, 1), + }, + { + val: 1, + f: IntBetween(0, 2), + }, + { + val: 1, + f: IntBetween(2, 3), + expectedErr: regexp.MustCompile("expected [\\w]+ to be in the range \\(2 - 3\\), got 1"), + }, + { + val: "1", + f: IntBetween(2, 3), + expectedErr: regexp.MustCompile("expected type of [\\w]+ to be int"), + }, + }) +} + +func TestValidationSringInSlice(t *testing.T) { + runTestCases(t, []testCase{ + { + val: "ValidValue", + f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), + }, + // ignore case + { + val: "VALIDVALUE", + f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, true), + }, + { + val: "VALIDVALUE", + f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), + expectedErr: regexp.MustCompile("expected [\\w]+ to be one of \\[ValidValue AnotherValidValue\\], got VALIDVALUE"), + }, + { + val: "InvalidValue", + f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), + expectedErr: regexp.MustCompile("expected [\\w]+ to be one of \\[ValidValue AnotherValidValue\\], got InvalidValue"), + }, + { + val: 1, + f: StringInSlice([]string{"ValidValue", "AnotherValidValue"}, false), + expectedErr: regexp.MustCompile("expected type of [\\w]+ to be string"), + }, + }) +} + +func runTestCases(t *testing.T, cases []testCase) { + matchErr := func(errs []error, r *regexp.Regexp) bool { + // err must match one provided + for _, err := range errs { + if r.MatchString(err.Error()) { + return true + } + } + + return false + } + + for i, tc := range cases { + _, errs := tc.f(tc.val, "test_property") + + if len(errs) == 0 && tc.expectedErr == nil { + continue + } + + if !matchErr(errs, tc.expectedErr) { + t.Fatalf("expected test case %d to produce error matching \"%s\", got %v", i, tc.expectedErr, errs) + } + } +}