From edb8e8904cee1a55eab293e8f8270a70ab7b9810 Mon Sep 17 00:00:00 2001 From: Chris Marchesi Date: Sun, 24 Sep 2017 18:18:31 -0700 Subject: [PATCH] helper/validation: Add NoZeroValues This adds NoZeroValues, a small SchemaValidateFunc that checks that a defined value is not a zero value. It's useful for situations where you want to keep someone from explicitly entering a zero value (ie: literally "0", or an empty string) on a required field, and want to catch it in the validation stage, versus during apply using GetOk. --- helper/validation/validation.go | 19 +++++++++++++++++ helper/validation/validation_test.go | 32 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/helper/validation/validation.go b/helper/validation/validation.go index 48940fafb..2ac1028cc 100644 --- a/helper/validation/validation.go +++ b/helper/validation/validation.go @@ -3,6 +3,7 @@ package validation import ( "fmt" "net" + "reflect" "regexp" "strings" @@ -105,6 +106,24 @@ func StringLenBetween(min, max int) schema.SchemaValidateFunc { } } +// NoZeroValues is a SchemaValidateFunc which tests if the provided value is +// not a zero value. It's useful in situations where you want to catch +// explicit zero values on things like required fields during validation. +func NoZeroValues(i interface{}, k string) (s []string, es []error) { + if reflect.ValueOf(i).Interface() == reflect.Zero(reflect.TypeOf(i)).Interface() { + switch reflect.TypeOf(i).Kind() { + case reflect.String: + es = append(es, fmt.Errorf("%s must not be empty", k)) + case reflect.Int, reflect.Float64: + es = append(es, fmt.Errorf("%s must not be zero", k)) + default: + // this validator should only ever be applied to TypeString, TypeInt and TypeFloat + panic(fmt.Errorf("can't use NoZeroValues with %T attribute %s", i, k)) + } + } + return +} + // CIDRNetwork returns a SchemaValidateFunc which tests if the provided value // is of type string, is in valid CIDR network notation, and has significant bits between min and max (inclusive) func CIDRNetwork(min, max int) schema.SchemaValidateFunc { diff --git a/helper/validation/validation_test.go b/helper/validation/validation_test.go index 5fbd02a32..4ed22a2e9 100644 --- a/helper/validation/validation_test.go +++ b/helper/validation/validation_test.go @@ -199,6 +199,38 @@ func TestValidateListUniqueStrings(t *testing.T) { }) } +func TestValidationNoZeroValues(t *testing.T) { + runTestCases(t, []testCase{ + { + val: "foo", + f: NoZeroValues, + }, + { + val: 1, + f: NoZeroValues, + }, + { + val: float64(1), + f: NoZeroValues, + }, + { + val: "", + f: NoZeroValues, + expectedErr: regexp.MustCompile("must not be empty"), + }, + { + val: 0, + f: NoZeroValues, + expectedErr: regexp.MustCompile("must not be zero"), + }, + { + val: float64(0), + f: NoZeroValues, + expectedErr: regexp.MustCompile("must not be zero"), + }, + }) +} + func runTestCases(t *testing.T, cases []testCase) { matchErr := func(errs []error, r *regexp.Regexp) bool { // err must match one provided