Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validation: add StringIsEmpty, StringIsWhitespace, StringIsNotEmpty, StringIsNotWhitespace, StringIsBase64, UUID, UUIDOrEmpty #294

Merged
merged 13 commits into from
Jan 14, 2020
79 changes: 79 additions & 0 deletions helper/validation/strings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package validation

import (
"encoding/base64"
"fmt"
"strings"
)

// StringIsNotEmpty is a ValidateFunc that ensures a string is not empty or consisting entirely of whitespace characters
func StringIsNotEmpty(i interface{}, k string) ([]string, []error) {
katbyte marked this conversation as resolved.
Show resolved Hide resolved
v, ok := i.(string)
if !ok {
return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
}

if v == "" {
return nil, []error{fmt.Errorf("expected %q to not be an empty string", k)}
}

return nil, nil
}

// StringIsNotEmpty is a ValidateFunc that ensures a string is not empty or consisting entirely of whitespace characters
func StringIsNotWhiteSpace(i interface{}, k string) ([]string, []error) {
v, ok := i.(string)
if !ok {
return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
}

if strings.TrimSpace(v) == "" {
return nil, []error{fmt.Errorf("expected %q to not be an empty string or whitespace", k)}
}

return nil, nil
}

// StringIsEmpty is a ValidateFunc that ensures a string has no characters
func StringIsEmpty(i interface{}, k string) ([]string, []error) {
v, ok := i.(string)
if !ok {
return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
}

if v != "" {
return nil, []error{fmt.Errorf("expected %q to be an empty string: got %v", k, v)}
}

return nil, nil
}

// StringIsEmpty is a ValidateFunc that ensures a string is composed of entirely whitespace
func StringIsWhiteSpace(i interface{}, k string) ([]string, []error) {
v, ok := i.(string)
if !ok {
return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
}

if strings.TrimSpace(v) != "" {
return nil, []error{fmt.Errorf("expected %q to be an empty string or whitespace: got %v", k, v)}
}

return nil, nil
}

// StringIsBase64 is a ValidateFunc that ensures a string can be parsed as Base64
func StringIsBase64(i interface{}, k string) (warnings []string, errors []error) {
// Empty string is not allowed
if warnings, errors = StringIsNotEmpty(i, k); len(errors) > 0 {
return
}

// NoEmptyStrings checks it is a string
v, _ := i.(string)
if _, err := base64.StdEncoding.DecodeString(v); err != nil {
errors = append(errors, fmt.Errorf("expected %q to be a base64 string, got %v", k, v))
}

return
}
276 changes: 276 additions & 0 deletions helper/validation/strings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
package validation

import (
"testing"
)

func TestValidationStringIsNotEmpty(t *testing.T) {
cases := map[string]struct {
Value interface{}
Error bool
}{
"NotString": {
Value: 7,
Error: true,
},
"Empty": {
Value: "",
Error: true,
},
"SingleSpace": {
Value: " ",
Error: false,
},
"MultipleSpaces": {
Value: " ",
Error: false,
},
"NewLine": {
Value: "\n",
Error: false,
},
"MultipleSymbols": {
Value: "-_-",
Error: false,
},
"Sentence": {
Value: "Hello kt's sentence.",
Error: false,
},
"StartsWithWhitespace": {
Value: " 7",
Error: false,
},
"EndsWithWhitespace": {
Value: "7 ",
Error: false,
},
}

for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
_, errors := StringIsNotEmpty(tc.Value, tn)

if len(errors) > 0 && !tc.Error {
t.Errorf("StringIsNotEmpty(%s) produced an unexpected error", tc.Value)
} else if len(errors) == 0 && tc.Error {
t.Errorf("StringIsNotEmpty(%s) did not error", tc.Value)
}
})
}
}

func TestValidationStringIsNotWhitespace(t *testing.T) {
cases := map[string]struct {
Value interface{}
Error bool
}{
"NotString": {
Value: 7,
Error: true,
},
"Empty": {
Value: "",
Error: true,
},
"SingleSpace": {
Value: " ",
Error: true,
},
"MultipleSpaces": {
Value: " ",
Error: true,
},
"CarriageReturn": {
Value: "\r",
Error: true,
},
"NewLine": {
Value: "\n",
Error: true,
},
"Tab": {
Value: "\t",
Error: true,
},
"FormFeed": {
Value: "\f",
Error: true,
},
"VerticalTab": {
Value: "\v",
Error: true,
},
"SingleChar": {
Value: "\v",
Error: true,
},
"MultipleChars": {
Value: "-_-",
Error: false,
},
"Sentence": {
Value: "Hello kt's sentence.",
Error: false,
},

"StartsWithWhitespace": {
Value: " 7",
Error: false,
},
"EndsWithWhitespace": {
Value: "7 ",
Error: false,
},
}

for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
_, errors := StringIsNotWhiteSpace(tc.Value, tn)

if len(errors) > 0 && !tc.Error {
t.Errorf("StringIsNotWhiteSpace(%s) produced an unexpected error", tc.Value)
} else if len(errors) == 0 && tc.Error {
t.Errorf("StringIsNotWhiteSpace(%s) did not error", tc.Value)
}
})
}
}

func TestValidationStringIsEmpty(t *testing.T) {
cases := map[string]struct {
Value interface{}
Error bool
}{
"NotString": {
Value: 7,
Error: true,
},
"Empty": {
Value: "",
Error: false,
},
"SingleSpace": {
Value: " ",
Error: true,
},
"MultipleSpaces": {
Value: " ",
Error: true,
},
"Sentence": {
Value: "Hello kt's sentence.",
Error: true,
},

"StartsWithWhitespace": {
Value: " 7",
Error: true,
},
"EndsWithWhitespace": {
Value: "7 ",
Error: true,
},
}

for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
_, errors := StringIsEmpty(tc.Value, tn)

if len(errors) > 0 && !tc.Error {
t.Errorf("StringIsEmpty(%s) produced an unexpected error", tc.Value)
} else if len(errors) == 0 && tc.Error {
t.Errorf("StringIsEmpty(%s) did not error", tc.Value)
}
})
}
}

func TestValidationStringIsWhiteSpace(t *testing.T) {
cases := map[string]struct {
Value interface{}
Error bool
}{
"NotString": {
Value: 7,
Error: true,
},
"Empty": {
Value: "",
Error: false,
},
"SingleSpace": {
Value: " ",
Error: false,
},
"MultipleSpaces": {
Value: " ",
Error: false,
},
"MultipleWhitespace": {
Value: " \t\n\f ",
Error: false,
},
"Sentence": {
Value: "Hello kt's sentence.",
Error: true,
},

"StartsWithWhitespace": {
Value: " 7",
Error: true,
},
"EndsWithWhitespace": {
Value: "7 ",
Error: true,
},
}

for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
_, errors := StringIsWhiteSpace(tc.Value, tn)

if len(errors) > 0 && !tc.Error {
t.Errorf("StringIsWhiteSpace(%s) produced an unexpected error", tc.Value)
} else if len(errors) == 0 && tc.Error {
t.Errorf("StringIsWhiteSpace(%s) did not error", tc.Value)
}
})
}
}

func TestValidationStringIsBase64(t *testing.T) {
cases := map[string]struct {
Value interface{}
Error bool
}{
"NotString": {
Value: 7,
Error: true,
},
"Empty": {
Value: "",
Error: true,
},
"NotBase64": {
Value: "Do'h!",
Error: true,
},
"Base64": {
Value: "RG8naCE=",
Error: false,
},
}

for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
_, errors := StringIsBase64(tc.Value, tn)

if len(errors) > 0 && !tc.Error {
t.Errorf("StringIsBase64(%s) produced an unexpected error", tc.Value)
} else if len(errors) == 0 && tc.Error {
t.Errorf("StringIsBase64(%s) did not error", tc.Value)
}
})
}
}
26 changes: 26 additions & 0 deletions helper/validation/uuid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package validation

import (
"fmt"
"regexp"

"github.com/hashicorp/go-uuid"
)

// UUIDRegExp is a Regular Expression that can be used to validate UUIDs
var UUIDRegExp = regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice 👍


// UUID is a ValidateFunc that ensures a string can be parsed as UUID
func UUID(i interface{}, k string) (warnings []string, errors []error) {
v, ok := i.(string)
if !ok {
errors = append(errors, fmt.Errorf("expected type of %q to be string", k))
return
}

if _, err := uuid.ParseUUID(v); err != nil {
errors = append(errors, fmt.Errorf("expected %q to be a valid UUID, got %v", k, v))
}

return warnings, errors
}
Loading