From 82a69d8925f0b9ef9413329944cbdee337555ec0 Mon Sep 17 00:00:00 2001 From: Brenden Soares Date: Fri, 15 Nov 2013 02:22:07 -0800 Subject: [PATCH 1/3] Adds more detail to validator default messages --- validation.go | 19 ++++++++++++++++++- validators.go | 18 +++++++++--------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/validation.go b/validation.go index bb06c7f46..05753adc2 100644 --- a/validation.go +++ b/validation.go @@ -6,6 +6,7 @@ import ( "net/url" "regexp" "runtime" + "strings" ) // Simple struct to store the Message & Key of a validation error @@ -151,9 +152,25 @@ func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult { INFO.Println("Failed to get Caller information to look up Validation key") } + // Format key value for display + var keyFormatted string + if key == "" { + keyFormatted = "Field" + } else { + var keyWords []string + for _, character := range key { + if int(character) >= int('A') && int(character) <= int('Z') { + keyWords = append(keyWords, " ") + } + keyWords = append(keyWords, strings.ToLower(string(character))) + } + keyWords[0] = strings.ToUpper(keyWords[0]) + keyFormatted = strings.Join(keyWords, "") + } + // Add the error to the validation context. err := &ValidationError{ - Message: chk.DefaultMessage(), + Message: fmt.Sprintf("%s %s", keyFormatted, chk.DefaultMessage()), Key: key, } v.Errors = append(v.Errors, err) diff --git a/validators.go b/validators.go index 27182c2c7..407e517d1 100644 --- a/validators.go +++ b/validators.go @@ -39,7 +39,7 @@ func (r Required) IsSatisfied(obj interface{}) bool { } func (r Required) DefaultMessage() string { - return "Required" + return "is required" } type Min struct { @@ -55,7 +55,7 @@ func (m Min) IsSatisfied(obj interface{}) bool { } func (m Min) DefaultMessage() string { - return fmt.Sprintln("Minimum is", m.Min) + return fmt.Sprintln("minimum is", m.Min) } type Max struct { @@ -71,7 +71,7 @@ func (m Max) IsSatisfied(obj interface{}) bool { } func (m Max) DefaultMessage() string { - return fmt.Sprintln("Maximum is", m.Max) + return fmt.Sprintln("maximum is", m.Max) } // Requires an integer to be within Min, Max inclusive. @@ -85,7 +85,7 @@ func (r Range) IsSatisfied(obj interface{}) bool { } func (r Range) DefaultMessage() string { - return fmt.Sprintln("Range is", r.Min.Min, "to", r.Max.Max) + return fmt.Sprintln("range is", r.Min.Min, "to", r.Max.Max) } // Requires an array or string to be at least a given length. @@ -105,7 +105,7 @@ func (m MinSize) IsSatisfied(obj interface{}) bool { } func (m MinSize) DefaultMessage() string { - return fmt.Sprintln("Minimum size is", m.Min) + return fmt.Sprintln("minimum size is", m.Min) } // Requires an array or string to be at most a given length. @@ -125,7 +125,7 @@ func (m MaxSize) IsSatisfied(obj interface{}) bool { } func (m MaxSize) DefaultMessage() string { - return fmt.Sprintln("Maximum size is", m.Max) + return fmt.Sprintln("maximum size is", m.Max) } // Requires an array or string to be exactly a given length. @@ -145,7 +145,7 @@ func (s Length) IsSatisfied(obj interface{}) bool { } func (s Length) DefaultMessage() string { - return fmt.Sprintln("Required length is", s.N) + return fmt.Sprintln("required length is", s.N) } // Requires a string to match a given regex. @@ -159,7 +159,7 @@ func (m Match) IsSatisfied(obj interface{}) bool { } func (m Match) DefaultMessage() string { - return fmt.Sprintln("Must match", m.Regexp) + return fmt.Sprintln("must match", m.Regexp) } var emailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?") @@ -169,5 +169,5 @@ type Email struct { } func (e Email) DefaultMessage() string { - return fmt.Sprintln("Must be a valid email address") + return fmt.Sprintln("must be a valid email address") } From 68cfd4dd0380273fbfa53127856f5236225c256e Mon Sep 17 00:00:00 2001 From: Brenden Soares Date: Mon, 18 Nov 2013 22:10:16 -0800 Subject: [PATCH 2/3] Changes uppercase check to be more concise --- validation.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validation.go b/validation.go index 05753adc2..0c2d71e76 100644 --- a/validation.go +++ b/validation.go @@ -7,6 +7,7 @@ import ( "regexp" "runtime" "strings" + "unicode" ) // Simple struct to store the Message & Key of a validation error @@ -159,7 +160,7 @@ func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult { } else { var keyWords []string for _, character := range key { - if int(character) >= int('A') && int(character) <= int('Z') { + if unicode.IsUpper(character) { keyWords = append(keyWords, " ") } keyWords = append(keyWords, strings.ToLower(string(character))) From a7ad0782ba25301206b6b09f879cab65e003caf9 Mon Sep 17 00:00:00 2001 From: Brenden Soares Date: Sat, 23 Nov 2013 23:11:42 -0800 Subject: [PATCH 3/3] Changes field formatting to be separate function; Adds validation test for field formatting function --- validation.go | 37 +++++++++++++++++++------------------ validation_test.go | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/validation.go b/validation.go index 0c2d71e76..1aeb5bb9c 100644 --- a/validation.go +++ b/validation.go @@ -6,7 +6,6 @@ import ( "net/url" "regexp" "runtime" - "strings" "unicode" ) @@ -153,25 +152,9 @@ func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult { INFO.Println("Failed to get Caller information to look up Validation key") } - // Format key value for display - var keyFormatted string - if key == "" { - keyFormatted = "Field" - } else { - var keyWords []string - for _, character := range key { - if unicode.IsUpper(character) { - keyWords = append(keyWords, " ") - } - keyWords = append(keyWords, strings.ToLower(string(character))) - } - keyWords[0] = strings.ToUpper(keyWords[0]) - keyFormatted = strings.Join(keyWords, "") - } - // Add the error to the validation context. err := &ValidationError{ - Message: fmt.Sprintf("%s %s", keyFormatted, chk.DefaultMessage()), + Message: fmt.Sprintf("%s %s", formatFieldName(key), chk.DefaultMessage()), Key: key, } v.Errors = append(v.Errors, err) @@ -261,6 +244,24 @@ func restoreValidationErrors(req *http.Request) ([]*ValidationError, error) { return errors, err } +// Format field name for display +func formatFieldName(field string) (formattedField string) { + if field == "" { + formattedField = "Field" + } else { + var words []rune + for _, character := range field { + if unicode.IsUpper(character) { + words = append(words, rune(' ')) + } + words = append(words, unicode.ToLower(rune(character))) + } + words[0] = unicode.ToUpper(words[0]) + formattedField = string(words) + } + return +} + // Register default validation keys for all calls to Controller.Validation.Func(). // Map from (package).func => (line => name of first arg to Validation func) // E.g. "myapp/controllers.helper" or "myapp/controllers.(*Application).Action" diff --git a/validation_test.go b/validation_test.go index 5f2ff7928..ed94d7470 100644 --- a/validation_test.go +++ b/validation_test.go @@ -74,3 +74,17 @@ func TestValidationNoKeepCookiePreviouslySet(t *testing.T) { t.Fatalf("cookie should be deleted") } } + +// Test that field names can be properly formatted for validation error messages +func TestFieldNameFormatting(t *testing.T) { + fieldAscii := "someField" + expectedAscii := "Some field" + fieldUnicode := "sömeϜield" + expectedUnicode := "Söme ϝield" + if formattedAscii := formatFieldName(fieldAscii); formattedAscii != expectedAscii { + t.Errorf("ASCII field formatting failed. Expecting %s, got %s", expectedAscii, formattedAscii) + } + if formattedUnicode := formatFieldName(fieldUnicode); formattedUnicode != expectedUnicode { + t.Errorf("ASCII field formatting failed. Expecting %s, got %s", expectedUnicode, formattedUnicode) + } +}