From b7cb7651a1ab26e6be8426a1c650c20530afc442 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 25 Feb 2025 23:30:44 -0800 Subject: [PATCH 1/4] Add MinLen validator --- ui/options.go | 10 ++++++-- ui/validators.go | 17 ++++++++++++ ui/validators_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/ui/options.go b/ui/options.go index 382c263..f4cb89a 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()) } +// WithValidateMinLen adds a custom validation function to a prompt that +// checks the input string meets the minimum length requirement. +func WithValidateMinLen(length int) Option { + return WithValidateFunc(MinLen(length)) +} + // 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..b73088e 100644 --- a/ui/validators.go +++ b/ui/validators.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net" + "regexp" "strings" "github.com/manifoldco/promptui" @@ -73,3 +74,19 @@ func YesNo() promptui.ValidateFunc { } } } + +// MinLen is a validation function that checks for a minimum length. +// An input length <= 0 indicates that the check should not be performed. +func MinLen(length int) promptui.ValidateFunc { + return func(s string) error { + if length <= 0 { + return nil + } + re := regexp.MustCompile(`\s+`) + next := re.ReplaceAllString(s, "") + if len(next) < length { + return fmt.Errorf("input does not meet minimum length requirement; must be at least %v characters", length) + } + return nil + } +} diff --git a/ui/validators_test.go b/ui/validators_test.go index 816079d..fe79eaf 100644 --- a/ui/validators_test.go +++ b/ui/validators_test.go @@ -90,3 +90,63 @@ func TestDNS(t *testing.T) { }) } } + +func TestMinLen(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-whitespace-characters", + length: 15, + input: " p \t\n#$%@#$ a s s ", + wantErr: true, + }, + { + name: "ignore-whitespace-characters-ok", + length: 10, + input: " p \t\n#$%@#$ a s s ", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotErr := MinLen(tt.length)(tt.input) != nil + if gotErr != tt.wantErr { + t.Errorf("MinLen(%v)(%s) = %v, want %v", tt.length, tt.input, gotErr, tt.wantErr) + } + }) + } +} From 231d02fdae1fbdd8d95792c10a6bc1e826f859c1 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 26 Feb 2025 23:02:02 -0800 Subject: [PATCH 2/4] Recommended changes from PR review - MinLen -> MinLength - regex -> strings.TrimSpace --- ui/options.go | 4 ++-- ui/validators.go | 13 +++++-------- ui/validators_test.go | 16 ++++++++-------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/ui/options.go b/ui/options.go index f4cb89a..bd5e1c3 100644 --- a/ui/options.go +++ b/ui/options.go @@ -145,8 +145,8 @@ func WithValidateNotEmpty() Option { // WithValidateMinLen adds a custom validation function to a prompt that // checks the input string meets the minimum length requirement. -func WithValidateMinLen(length int) Option { - return WithValidateFunc(MinLen(length)) +func WithValidateMinLength(minLength int) Option { + return WithValidateFunc(MinLength(minLength)) } // WithValidateYesNo adds a custom validation function to a prompt for a Yes/No diff --git a/ui/validators.go b/ui/validators.go index b73088e..2acc3e8 100644 --- a/ui/validators.go +++ b/ui/validators.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net" - "regexp" "strings" "github.com/manifoldco/promptui" @@ -75,17 +74,15 @@ func YesNo() promptui.ValidateFunc { } } -// MinLen is a validation function that checks for a minimum length. +// MinLength is a validation function that checks for a minimum length. // An input length <= 0 indicates that the check should not be performed. -func MinLen(length int) promptui.ValidateFunc { +func MinLength(minLength int) promptui.ValidateFunc { return func(s string) error { - if length <= 0 { + if minLength <= 0 { return nil } - re := regexp.MustCompile(`\s+`) - next := re.ReplaceAllString(s, "") - if len(next) < length { - return fmt.Errorf("input does not meet minimum length requirement; must be at least %v characters", length) + if len(strings.TrimSpace(s)) < 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 fe79eaf..8756cbb 100644 --- a/ui/validators_test.go +++ b/ui/validators_test.go @@ -91,7 +91,7 @@ func TestDNS(t *testing.T) { } } -func TestMinLen(t *testing.T) { +func TestMinLength(t *testing.T) { tests := []struct { name string length int @@ -129,23 +129,23 @@ func TestMinLen(t *testing.T) { wantErr: true, }, { - name: "ignore-whitespace-characters", - length: 15, - input: " p \t\n#$%@#$ a s s ", + name: "ignore-pre-post-whitespace-characters", + length: 5, + input: " pass ", wantErr: true, }, { name: "ignore-whitespace-characters-ok", - length: 10, - input: " p \t\n#$%@#$ a s s ", + length: 4, + input: " pass ", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotErr := MinLen(tt.length)(tt.input) != nil + gotErr := MinLength(tt.length)(tt.input) != nil if gotErr != tt.wantErr { - t.Errorf("MinLen(%v)(%s) = %v, want %v", tt.length, tt.input, gotErr, tt.wantErr) + t.Errorf("MinLength(%v)(%s) = %v, want %v", tt.length, tt.input, gotErr, tt.wantErr) } }) } From 81ebe1fcf35ef21d4279593ace412ac3e0266aa6 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 27 Feb 2025 10:48:57 -0800 Subject: [PATCH 3/4] Use TrimRightFunc instead of TrimSpace --- ui/validators.go | 3 ++- ui/validators_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/validators.go b/ui/validators.go index 2acc3e8..57e4910 100644 --- a/ui/validators.go +++ b/ui/validators.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "strings" + "unicode" "github.com/manifoldco/promptui" ) @@ -81,7 +82,7 @@ func MinLength(minLength int) promptui.ValidateFunc { if minLength <= 0 { return nil } - if len(strings.TrimSpace(s)) < minLength { + 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 8756cbb..5b06044 100644 --- a/ui/validators_test.go +++ b/ui/validators_test.go @@ -129,14 +129,14 @@ func TestMinLength(t *testing.T) { wantErr: true, }, { - name: "ignore-pre-post-whitespace-characters", - length: 5, + name: "ignore-post-whitespace-characters", + length: 7, input: " pass ", wantErr: true, }, { - name: "ignore-whitespace-characters-ok", - length: 4, + name: "ignore-post-whitespace-characters-ok", + length: 6, input: " pass ", wantErr: false, }, From 7c65086fa17b4094806ea5a9e5387d13c50130d1 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Thu, 27 Feb 2025 10:51:18 -0800 Subject: [PATCH 4/4] Fix function name in comment --- ui/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/options.go b/ui/options.go index bd5e1c3..b1f7d45 100644 --- a/ui/options.go +++ b/ui/options.go @@ -143,7 +143,7 @@ func WithValidateNotEmpty() Option { return WithValidateFunc(NotEmpty()) } -// WithValidateMinLen adds a custom validation function to a prompt that +// 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))