From 583afea7309ef2d842d209af135a71e5fe6e139d Mon Sep 17 00:00:00 2001 From: "Stanislav N. aka pztrn" Date: Wed, 11 Dec 2019 13:56:03 +0500 Subject: [PATCH] Added ability to run multiple validators with one call (ValidateMany) and changed parameters order in Validate(). --- validations.go | 63 ++++++++++++------ validations_test.go | 152 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 191 insertions(+), 24 deletions(-) diff --git a/validations.go b/validations.go index d5eea39..95364b1 100644 --- a/validations.go +++ b/validations.go @@ -42,6 +42,49 @@ func RegisterValidator(validatorName string, validator validators.ValidatorFunc) return nil } +// Validate launches validation function and returns it's result to +// caller. Optional might be used for passing additional options to +// validators. +func Validate(thing interface{}, validatorName string, optional ...interface{}) []interface{} { + var errs []interface{} + + validator, found := registeredValidators[validatorName] + + if !found { + errs = append(errs, ErrValidatorNotRegistered) + return errs + } + + errs1 := validator(thing, optional...) + if len(errs1) > 0 { + errs = append(errs, errs1...) + } + + return errs +} + +// ValidateMany launches many validators using one-line-call. +// Optional might be used for passing parameters to validators, wher +// key is a validator name and value (which is []interface{}) +// is a slice of parameters. +func ValidateMany(thing interface{}, validatorNames []string, optional map[string][]interface{}) []interface{} { + var errs []interface{} + + for _, validator := range validatorNames { + validatorParams, found := optional[validator] + if !found { + validatorParams = make([]interface{}, 0) + } + + errs1 := Validate(thing, validator, validatorParams...) + if len(errs1) > 0 { + errs = append(errs, errs1...) + } + } + + return errs +} + // UnregisterValidator removes registered validator from list of known // validators. func UnregisterValidator(validatorName string) error { @@ -63,23 +106,3 @@ func UnregisterValidator(validatorName string) error { return nil } - -// Validate launches validation function and returns it's result to -// caller. -func Validate(validatorName string, thing interface{}, optional ...interface{}) []interface{} { - var errs []interface{} - - validator, found := registeredValidators[validatorName] - - if !found { - errs = append(errs, ErrValidatorNotRegistered) - return errs - } - - errs1 := validator(thing, optional...) - if len(errs1) > 0 { - errs = append(errs, errs1...) - } - - return errs -} diff --git a/validations_test.go b/validations_test.go index 15e7570..3557e5d 100644 --- a/validations_test.go +++ b/validations_test.go @@ -105,7 +105,7 @@ func TestValidate(t *testing.T) { return errs }) - errs := Validate("string_test1", testString, nil) + errs := Validate(testString, "string_test1", nil) require.NotNil(t, errs) require.Len(t, errs, 1) } @@ -131,7 +131,7 @@ func BenchmarkValidate(b *testing.B) { } if strings.Contains(stringToValidate, "$") { - errs = append(errs, errors.New("string starts with whitespace, invalid")) + errs = append(errs, errors.New("string contains dollar sign, invalid")) } return errs @@ -140,7 +140,7 @@ func BenchmarkValidate(b *testing.B) { b.StartTimer() for i := 0; i < b.N; i++ { - _ = Validate("string_test1", testString) + _ = Validate(testString, "string_test1") } } @@ -179,7 +179,151 @@ func BenchmarkValidateAsync(b *testing.B) { w.Add(1) go func() { - _ = Validate("string_test1", testString) + _ = Validate(testString, "string_test1") + + w.Done() + }() + + w.Wait() + } +} + +func TestValidateMany(t *testing.T) { + initializeValidatorsStorage() + + testString := " I am test string" + + _ = RegisterValidator("string_test1", func(thing interface{}, optional ...interface{}) []interface{} { + var errs []interface{} + + stringToValidate, ok := thing.(string) + if !ok { + errs = append(errs, errors.New("not a string")) + return errs + } + + if strings.HasPrefix(stringToValidate, " ") { + errs = append(errs, errors.New("string starts with whitespace, invalid")) + } + + return errs + }) + + _ = RegisterValidator("string_test2", func(thing interface{}, optional ...interface{}) []interface{} { + var errs []interface{} + + stringToValidate, ok := thing.(string) + if !ok { + errs = append(errs, errors.New("not a string")) + return errs + } + + if strings.HasSuffix(stringToValidate, " ") { + errs = append(errs, errors.New("string ends with whitespace, invalid")) + } + + return errs + }) + + errs := ValidateMany(testString, []string{"string_test1", "string_test2"}, nil) + require.NotNil(t, errs) + require.Len(t, errs, 1) +} + +func BenchmarkValidateMany(b *testing.B) { + b.StopTimer() + + initializeValidatorsStorage() + + testString := " I am test $tring" + + _ = RegisterValidator("string_test1", func(thing interface{}, optional ...interface{}) []interface{} { + var errs []interface{} + + stringToValidate, ok := thing.(string) + if !ok { + errs = append(errs, errors.New("not a string")) + return errs + } + + if strings.HasPrefix(stringToValidate, " ") { + errs = append(errs, errors.New("string starts with whitespace, invalid")) + } + + return errs + }) + + _ = RegisterValidator("string_test2", func(thing interface{}, optional ...interface{}) []interface{} { + var errs []interface{} + + stringToValidate, ok := thing.(string) + if !ok { + errs = append(errs, errors.New("not a string")) + return errs + } + + if strings.Contains(stringToValidate, "$") { + errs = append(errs, errors.New("string contains dollar sign, invalid")) + } + + return errs + }) + + b.StartTimer() + + for i := 0; i < b.N; i++ { + _ = ValidateMany(testString, []string{"string_test1", "string_test2"}, nil) + } +} + +func BenchmarkValidateManyAsync(b *testing.B) { + b.StopTimer() + + initializeValidatorsStorage() + + testString := " I am test $tring" + + _ = RegisterValidator("string_test1", func(thing interface{}, optional ...interface{}) []interface{} { + var errs []interface{} + + stringToValidate, ok := thing.(string) + if !ok { + errs = append(errs, errors.New("not a string")) + return errs + } + + if strings.HasPrefix(stringToValidate, " ") { + errs = append(errs, errors.New("string starts with whitespace, invalid")) + } + + return errs + }) + + _ = RegisterValidator("string_test2", func(thing interface{}, optional ...interface{}) []interface{} { + var errs []interface{} + + stringToValidate, ok := thing.(string) + if !ok { + errs = append(errs, errors.New("not a string")) + return errs + } + + if strings.Contains(stringToValidate, "$") { + errs = append(errs, errors.New("string contains dollar sign, invalid")) + } + + return errs + }) + + b.StartTimer() + + var w sync.WaitGroup + + for i := 0; i < b.N; i++ { + w.Add(1) + + go func() { + _ = ValidateMany(testString, []string{"string_test1", "string_test2"}, nil) w.Done() }()