🇧🇷 CPF validation in Go

Merge pull request #3 from cuducos/to-publish

Wrap this as a Go module

authored by

Eduardo Cuducos and committed by
GitHub
d1965e8b 051df1d4

+92 -39
+2 -2
.github/workflows/tests.yml
··· 9 9 runs-on: ubuntu-latest 10 10 steps: 11 11 12 - - name: Set up Go 1.13 12 + - name: Set up Go 1.14 13 13 uses: actions/setup-go@v1 14 14 with: 15 - go-version: 1.13 15 + go-version: 1.14 16 16 id: go 17 17 18 18 - name: Check out code into the Go module directory
+28 -5
README.md
··· 1 - # Go CPF ![Tests](https://github.com/cuducos/go-cpf/workflows/Tests/badge.svg) 1 + # Go CPF [![Tests](https://github.com/cuducos/go-cpf/workflows/Tests/badge.svg)]()[![GoDoc](https://godoc.org/github.com/cuducos/go-cpf?status.svg)](https://godoc.org/github.com/cuducos/go-cpf)![Go version](https://img.shields.io/github/go-mod/go-version/cuducos/go-cpf) 2 + 3 + A Go module to validate CPF numbers (Brazilian unique identifier for the Federal Revenue). 4 + 5 + ```go 6 + package main 7 + 8 + import "github.com/cuducos/go-cpf" 9 + 10 + 11 + func main() { 12 + // these return true 13 + cpf.IsValid("23858488135") 14 + cpf.IsValid("238.584.881-35") 15 + 16 + // these return false 17 + cpf.IsValid("111.111.111-11") 18 + cpf.IsValid("123.456.769/01") 19 + cpf.IsValid("ABC.DEF.GHI-JK") 20 + cpf.IsValid("123") 2 21 3 - Three things about this repo: 22 + // this returns 11111111111 23 + cpf.Unmask("111.111.111-11") 4 24 5 - 1. I just started to learn [Go](https://golang.org/) with [_Learn Go With Tests_](https://quii.gitbook.io/learn-go-with-tests/) and this CPF (Brazilian unique identifier for the Federal Revenue) validation script is actually **my very first lines in Go** (except the ones from the book) 6 - 2. I'm sharing it here to get **feedback** ❤️ 7 - 3. It's not a proper or usable package yet, I just expect **`go test`** to pass : ) 25 + // this returns 111.111.111-11 26 + cpf.Mask("11111111111") 27 + } 28 + ``` 29 + 30 + I started to learn [Go](https://golang.org/) with [_Learn Go With Tests_](https://quii.gitbook.io/learn-go-with-tests/) and this CPF (Brazilian unique identifier for the Federal Revenue) validation script is actually **my very first lines in Go** (except the ones from the book). I'm sharing it here to get **feedback** ❤️
+12 -18
cpf.go
··· 7 7 "strings" 8 8 ) 9 9 10 - //auxiliar type and variable to build a set 10 + //These are auxiliar type and variable to build a set 11 11 type void struct{} 12 12 13 13 var member void 14 14 15 - //Cpf type 16 - type Cpf string 17 - 18 - func (c Cpf) String() string { 19 - return string(c) 20 - } 21 15 22 16 func checksum(ds []int64) int64 { 23 17 var s int64 ··· 31 25 return r 32 26 } 33 27 34 - //IsValid checks whether Cpf number is valid or not 35 - func (c Cpf) IsValid() bool { 36 - u := c.Unmask() 28 + //IsValid checks whether CPF number is valid or not 29 + func IsValid(n string) bool { 30 + u := Unmask(n) 37 31 38 32 if len(u) != 11 { 39 33 return false ··· 50 44 s[c] = member 51 45 } 52 46 53 - //If all digits are the same, the Cpf is not valid 47 + //If all digits are the same, the CPF is not valid 54 48 if len(s) == 1 { 55 49 return false 56 50 } ··· 58 52 return checksum(ds[:9]) == ds[9] && checksum(ds[:10]) == ds[10] 59 53 } 60 54 61 - //Mask returns the Cpf number formatted 62 - func (c Cpf) Mask() string { 63 - u := c.Unmask() 55 + //Mask returns the CPF number formatted 56 + func Mask(n string) string { 57 + u := Unmask(n) 64 58 if len(u) != 11 { 65 - return string(c) 59 + return n 66 60 } 67 61 return fmt.Sprintf("%s.%s.%s-%s", u[:3], u[3:6], u[6:9], u[9:]) 68 62 } 69 63 70 - //Unmask removes any non-digit (numeric) from the Cpf 71 - func (c Cpf) Unmask() string { 72 - return regexp.MustCompile(`\D`).ReplaceAllString(string(c), "") 64 + //Unmask removes any non-digit (numeric) from the CPF number 65 + func Unmask(n string) string { 66 + return regexp.MustCompile(`\D`).ReplaceAllString(n, "") 73 67 }
+47 -14
cpf_test.go
··· 1 1 package cpf 2 2 3 - import "testing" 3 + import ( 4 + "fmt" 5 + "testing" 6 + ) 4 7 5 8 func TestMask(t *testing.T) { 6 9 for _, tc := range []struct { ··· 11 14 {"123456", "123456"}, 12 15 {"11223344556677889900", "11223344556677889900"}, 13 16 } { 14 - if got := Cpf(tc.cpf).Mask(); tc.expected != got { 15 - t.Errorf("Cpf(\"%s\").Mask() = %v; want %s", tc.cpf, got, tc.expected) 17 + if got := Mask(tc.cpf); tc.expected != got { 18 + t.Errorf("Mask(\"%s\") = %v; expected %s", tc.cpf, got, tc.expected) 16 19 } 17 20 } 18 21 } 19 22 20 23 func TestUnmask(t *testing.T) { 21 - if got := Cpf("111.111.111-11").Unmask(); "11111111111" != got { 22 - t.Errorf("Cpf(\"111.111.111-11\").Unmask() = %v; want 11111111111", got) 24 + if got := Unmask("111.111.111-11"); "11111111111" != got { 25 + t.Errorf("Unmask(\"111.111.111-11\") = %v; want 11111111111", got) 23 26 } 24 27 } 25 28 26 29 func TestIsValid(t *testing.T) { 27 30 for _, tc := range []struct { 28 - cpf Cpf 31 + cpf string 29 32 expected bool 30 33 }{ 31 - {Cpf("23858488135"), true}, 32 - {Cpf("238.584.881-35"), true}, 33 - {Cpf("123"), false}, 34 - {Cpf("111.111.111-11"), false}, 35 - {Cpf("123.456.769/01"), false}, 36 - {Cpf("ABC.DEF.GHI-JK"), false}, 34 + {"23858488135", true}, 35 + {"238.584.881-35", true}, 36 + {"123", false}, 37 + {"111.111.111-11", false}, 38 + {"123.456.769/01", false}, 39 + {"ABC.DEF.GHI-JK", false}, 37 40 } { 38 - if got := tc.cpf.IsValid(); tc.expected != got { 39 - t.Errorf("Cpf(%v).IsValid() = %v; want %v", tc.cpf, got, tc.expected) 41 + if got := IsValid(tc.cpf); tc.expected != got { 42 + t.Errorf("IsValid(%v) = %v; expected %v", tc.cpf, got, tc.expected) 40 43 } 41 44 } 42 45 } 46 + 47 + func ExampleIsValid_validUnmasked() { 48 + fmt.Println(IsValid("23858488135")) 49 + // Output: true 50 + } 51 + 52 + func ExampleIsValid_validMasked() { 53 + fmt.Println(IsValid("238.584.881-35")) 54 + // Output: true 55 + } 56 + 57 + func ExampleIsValid_invalid() { 58 + fmt.Println(IsValid("111.111.111-11")) 59 + // Output: false 60 + } 61 + 62 + func ExampleMask_valid() { 63 + fmt.Println(Mask("11111111111")) 64 + // Output: 111.111.111-11 65 + } 66 + 67 + func ExampleMask_invalid() { 68 + fmt.Println(Mask("42")) 69 + // Output: 42 70 + } 71 + 72 + func ExampleUnmask() { 73 + fmt.Println(Unmask("111.111.111-11")) 74 + // Output: 11111111111 75 + }
+3
go.mod
··· 1 + module github.com/cuducos/go-cpf 2 + 3 + go 1.14