diff --git a/ui/options.go b/ui/options.go index 382c263..b1f7d45 100644 --- a/ui/options.go +++ b/ui/options.go @@ -138,11 +138,17 @@ func WithValidateFunc(fn func(string) error) Option { } // WithValidateNotEmpty adds a custom validation function to a prompt that -// checks that the propted string is not empty. +// checks that the prompted string is not empty. func WithValidateNotEmpty() Option { return WithValidateFunc(NotEmpty()) } +// WithValidateMinLength adds a custom validation function to a prompt that +// checks the input string meets the minimum length requirement. +func WithValidateMinLength(minLength int) Option { + return WithValidateFunc(MinLength(minLength)) +} + // WithValidateYesNo adds a custom validation function to a prompt for a Yes/No // prompt. func WithValidateYesNo() Option { @@ -167,6 +173,6 @@ func WithValidateRegexp(re string) Option { if rx.MatchString(s) { return nil } - return fmt.Errorf("%s does not match the regular expresion %s", s, re) + return fmt.Errorf("%s does not match the regular expression %s", s, re) }) } diff --git a/ui/validators.go b/ui/validators.go index 7d8b603..57e4910 100644 --- a/ui/validators.go +++ b/ui/validators.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "strings" + "unicode" "github.com/manifoldco/promptui" ) @@ -73,3 +74,17 @@ func YesNo() promptui.ValidateFunc { } } } + +// MinLength is a validation function that checks for a minimum length. +// An input length <= 0 indicates that the check should not be performed. +func MinLength(minLength int) promptui.ValidateFunc { + return func(s string) error { + if minLength <= 0 { + return nil + } + if len(strings.TrimRightFunc(s, unicode.IsSpace)) < minLength { + return fmt.Errorf("input does not meet minimum length requirement; must be at least %v characters", minLength) + } + return nil + } +} diff --git a/ui/validators_test.go b/ui/validators_test.go index 816079d..5b06044 100644 --- a/ui/validators_test.go +++ b/ui/validators_test.go @@ -90,3 +90,63 @@ func TestDNS(t *testing.T) { }) } } + +func TestMinLength(t *testing.T) { + tests := []struct { + name string + length int + input string + wantErr bool + }{ + { + name: "negative", + length: -5, + input: "foobar", + wantErr: false, + }, + { + name: "zero", + length: 0, + input: "localhost", + wantErr: false, + }, + { + name: "greater-than-min-length", + length: 5, + input: "foobar", + wantErr: false, + }, + { + name: "equal-min-length", + length: 6, + input: "foobar", + wantErr: false, + }, + { + name: "less-than-min-length", + length: 8, + input: "foobar", + wantErr: true, + }, + { + name: "ignore-post-whitespace-characters", + length: 7, + input: " pass ", + wantErr: true, + }, + { + name: "ignore-post-whitespace-characters-ok", + length: 6, + input: " pass ", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotErr := MinLength(tt.length)(tt.input) != nil + if gotErr != tt.wantErr { + t.Errorf("MinLength(%v)(%s) = %v, want %v", tt.length, tt.input, gotErr, tt.wantErr) + } + }) + } +}