Stanislav N. aka pztrn
d26b8f4262
All checks were successful
continuous-integration/drone Build is passing
440 lines
9.7 KiB
Go
440 lines
9.7 KiB
Go
// Valiwork - validations that works.
|
|
// Copyright (c) 2020 by Stanislav Nikitin <pztrn@pztrn.name>
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
package valiwork
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.dev.pztrn.name/valiwork/validators"
|
|
)
|
|
|
|
const (
|
|
testString = " I am test $tring"
|
|
)
|
|
|
|
// nolint:paralleltest
|
|
func TestRegisterValidator(t *testing.T) {
|
|
initializeValidatorsStorage()
|
|
|
|
testCases := []struct {
|
|
ValidatorFunc validators.ValidatorFunc
|
|
ValidatorName string
|
|
ShouldFail bool
|
|
}{
|
|
{
|
|
ValidatorName: "string_test_validator",
|
|
ValidatorFunc: func(thing interface{}, optional ...interface{}) []interface{} {
|
|
return nil
|
|
},
|
|
ShouldFail: false,
|
|
},
|
|
// This case is about registering same validator function again.
|
|
{
|
|
ValidatorName: "string_test_validator",
|
|
ValidatorFunc: func(thing interface{}, optional ...interface{}) []interface{} {
|
|
return nil
|
|
},
|
|
ShouldFail: true,
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
err := RegisterValidator(testCase.ValidatorName, testCase.ValidatorFunc)
|
|
|
|
if !testCase.ShouldFail {
|
|
require.Nil(t, err)
|
|
} else {
|
|
require.NotNil(t, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkRegisterValidator(b *testing.B) {
|
|
initializeValidatorsStorage()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_ = RegisterValidator("string_test_validator_"+strconv.Itoa(i),
|
|
func(thing interface{}, optional ...interface{}) []interface{} {
|
|
return nil
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func BenchmarkRegisterValidatorAsync(b *testing.B) {
|
|
initializeValidatorsStorage()
|
|
|
|
var waiter sync.WaitGroup
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
waiter.Add(1)
|
|
|
|
go func() {
|
|
_ = RegisterValidator("string_test_validator_"+strconv.Itoa(i),
|
|
func(thing interface{}, optional ...interface{}) []interface{} {
|
|
return nil
|
|
},
|
|
)
|
|
|
|
waiter.Done()
|
|
}()
|
|
|
|
waiter.Wait()
|
|
}
|
|
}
|
|
|
|
// nolint:paralleltest
|
|
func TestValidate(t *testing.T) {
|
|
initializeValidatorsStorage()
|
|
|
|
_ = 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
|
|
})
|
|
|
|
errs := Validate(testString, "string_test1", nil)
|
|
require.NotNil(t, errs)
|
|
require.Len(t, errs, 1)
|
|
}
|
|
|
|
func BenchmarkValidate(b *testing.B) {
|
|
b.StopTimer()
|
|
|
|
initializeValidatorsStorage()
|
|
|
|
_ = 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"))
|
|
}
|
|
|
|
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++ {
|
|
_ = Validate(testString, "string_test1")
|
|
}
|
|
}
|
|
|
|
func BenchmarkValidateAsync(b *testing.B) {
|
|
b.StopTimer()
|
|
|
|
initializeValidatorsStorage()
|
|
|
|
_ = 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"))
|
|
}
|
|
|
|
if strings.Contains(stringToValidate, "$") {
|
|
errs = append(errs, errors.New("string starts with whitespace, invalid"))
|
|
}
|
|
|
|
return errs
|
|
})
|
|
|
|
b.StartTimer()
|
|
|
|
var waiter sync.WaitGroup
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
waiter.Add(1)
|
|
|
|
go func() {
|
|
_ = Validate(testString, "string_test1")
|
|
|
|
waiter.Done()
|
|
}()
|
|
|
|
waiter.Wait()
|
|
}
|
|
}
|
|
|
|
// nolint:paralleltest
|
|
func TestValidateMany(t *testing.T) {
|
|
initializeValidatorsStorage()
|
|
|
|
_ = 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()
|
|
|
|
_ = 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()
|
|
|
|
_ = 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 waiter sync.WaitGroup
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
waiter.Add(1)
|
|
|
|
go func() {
|
|
_ = ValidateMany(testString, []string{"string_test1", "string_test2"}, nil)
|
|
|
|
waiter.Done()
|
|
}()
|
|
|
|
waiter.Wait()
|
|
}
|
|
}
|
|
|
|
// nolint:paralleltest
|
|
func TestUnregisterValidator(t *testing.T) {
|
|
initializeValidatorsStorage()
|
|
|
|
testCases := []struct {
|
|
ValidatorFunc validators.ValidatorFunc
|
|
ValidatorName string
|
|
}{
|
|
{
|
|
ValidatorName: "string_test_validator",
|
|
ValidatorFunc: func(thing interface{}, optional ...interface{}) []interface{} {
|
|
return nil
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
err := RegisterValidator(testCase.ValidatorName, testCase.ValidatorFunc)
|
|
require.Nil(t, err)
|
|
|
|
err1 := UnregisterValidator(testCase.ValidatorName)
|
|
require.Nil(t, err1)
|
|
}
|
|
}
|
|
|
|
// nolint:paralleltest
|
|
func TestUnregisterValidatorNotRegisteredValidator(t *testing.T) {
|
|
initializeValidatorsStorage()
|
|
|
|
err := UnregisterValidator("this is definitely not registered thing")
|
|
require.NotNil(t, err)
|
|
}
|
|
|
|
func BenchmarkUnregisterValidator(b *testing.B) {
|
|
b.StopTimer()
|
|
|
|
initializeValidatorsStorage()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_ = RegisterValidator("string_test_validator_"+strconv.Itoa(i),
|
|
func(thing interface{}, optional ...interface{}) []interface{} {
|
|
return nil
|
|
},
|
|
)
|
|
}
|
|
|
|
b.StartTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_ = UnregisterValidator("string_test_validator_" + strconv.Itoa(i))
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnregisterValidatorAsync(b *testing.B) {
|
|
b.StopTimer()
|
|
|
|
initializeValidatorsStorage()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_ = RegisterValidator("string_test_validator_"+strconv.Itoa(i),
|
|
func(thing interface{}, optional ...interface{}) []interface{} {
|
|
return nil
|
|
},
|
|
)
|
|
}
|
|
|
|
var waiter sync.WaitGroup
|
|
|
|
b.StartTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
waiter.Add(1)
|
|
|
|
go func() {
|
|
_ = UnregisterValidator("string_test_validator_" + strconv.Itoa(i))
|
|
|
|
waiter.Done()
|
|
}()
|
|
|
|
waiter.Wait()
|
|
}
|
|
}
|