Skip to content

Commit

Permalink
implement new Validator interface and new CEP validator
Browse files Browse the repository at this point in the history
  • Loading branch information
flavioltonon committed Sep 30, 2020
1 parent 9a12a8a commit 9d802f7
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 1 deletion.
38 changes: 38 additions & 0 deletions cep.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package brazil

import (
"fmt"
"math/rand"
"regexp"
"strconv"
"time"
)

// NewCEPValidator creates a CEP number validator, containing inner mask and validation functions which can be
// accessed via Mask and Validate methods.
func NewCEPValidator() Validator {
return &validator{
maskFunc: func(value string) string {
value = onlyDigits(value)

return fmt.Sprintf("%s-%s", value[:5], value[5:])
},
validationFunc: func(value string) error {
value = onlyDigits(value)

if !regexp.MustCompile(`^\d{8}$`).MatchString(value) {
return ErrInvalidCEPFormat
}

return nil
},
}
}

// RandomCEPNumber generates a random valid CEP number
func RandomCEPNumber() string {
seed := time.Now().UnixNano()
source := rand.NewSource(seed)
r := rand.New(source)
return strconv.Itoa(r.Intn(89999999) + 10000000)
}
32 changes: 32 additions & 0 deletions cep_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package brazil_test

import (
"testing"

. "github.com/flavioltonon/go-brazil"

"github.com/stretchr/testify/assert"
)

func TestCEP(t *testing.T) {
c := NewCEPValidator()

t.Run("When parsing a CEP with an valid number, no errors should be returned and cep should contain a value", func(t *testing.T) {
assert.NoError(t, c.Validate("12345-678"))
})

t.Run("When parsing a CEP with an valid masked number, no errors should be returned and cep should contain a value", func(t *testing.T) {
assert.NoError(t, c.Validate("12345678"))
})

t.Run("When parsing a CEP with an invalid input number, an ErrInvalidCEPFormat should be returned and cep should be nil", func(t *testing.T) {
assert.Error(t, c.Validate("123456789"), ErrInvalidCEPFormat)
})

t.Run("When a random CEP number is generated, it should be successfully validated", func(t *testing.T) {
for i := 0; i < 1000; i++ {
value := RandomCEPNumber()
assert.NoError(t, c.Validate(value))
}
})
}
3 changes: 3 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ var (
ErrIncorrectLenghtPISNumber = errors.New("PIS numbers must contain 11 or 13 numbers")
ErrInvalidPISNumber = errors.New("PIS number input is not valid")

ErrInvalidCEPFormat = errors.New("CEP format input is different than expected. Expected format: XXXXX-XXX, XXXXXXXX (e.g. 12345-678, 12345678)")
ErrInvalidCEPLength = errors.New("CEP numbers must contain 9 digits")

ErrIncorrectFormatDate = errors.New("Date format input is different than expected. Expected format: DD/MM/YYYY")
ErrInvalidYearLimits = errors.New("Date minYear must be lower than maxYear and higher than zero")
ErrNotPastDate = errors.New("Date must be in the past")
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/flavioltonon/go-brazil

go 1.13

require github.com/smartystreets/goconvey v1.6.4
require (
github.com/smartystreets/goconvey v1.6.4
github.com/stretchr/testify v1.6.1
)
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
27 changes: 27 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package brazil

import "unicode"

func onlyDigits(input string) string {
norm := make([]rune, 0)

for _, r := range input {
if unicode.IsDigit(r) {
norm = append(norm, r)
}
}

return string(norm)
}

func onlyLetters(input string) string {
norm := make([]rune, 0)

for _, r := range input {
if unicode.IsLetter(r) {
norm = append(norm, r)
}
}

return string(norm)
}
29 changes: 29 additions & 0 deletions validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package brazil

type Validator interface {
Validate(value string) error
}

type Maskable interface {
Mask(value string) string
}

type MaskableValidator interface {
Maskable
Validator
}

type validator struct {
maskFunc func(value string) string
validationFunc func(value string) error
}

// Validate checks if the input value is valid according to the validator rules and returns an error if it isn't.
func (v *validator) Validate(value string) error {
return v.validationFunc(value)
}

// Mask applies the validator mask to a value. If the value is not valid, the masking may not be completely correct and the method may panic.
func (v *validator) Mask(value string) string {
return v.maskFunc(value)
}

0 comments on commit 9d802f7

Please sign in to comment.