Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/mock_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ func GenerateMockExample() {
fmt.Println(constants.HeaderMain)
fmt.Println(constants.SubHeader)

fmt.Printf("Person: %s %s, %s, %d years old\n",
person_mock.FirstNameMale, person_mock.LastName, person_mock.Gender, person_mock.Age)
fmt.Printf("Person: %s %s, %s, %d years old, CPF: %s\n",
person_mock.FirstNameMale, person_mock.LastName, person_mock.Gender, person_mock.Age, person_mock.CPF)
fmt.Printf("Address: %s, %d - %s, %s (%s) - %s\n",
address_mock.Street, address_mock.Number, address_mock.City, address_mock.State, address_mock.UF, address_mock.ZIP)
fmt.Printf("Phone: (%s) %s\n", phone_mock.AreaCode, phone_mock.Number)
Expand Down
7 changes: 7 additions & 0 deletions pkg/mocai/entities/cpf/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package cpf

import "errors"

var (
ErrInvalidCPF = errors.New("invalid CPF")
)
58 changes: 58 additions & 0 deletions pkg/mocai/entities/cpf/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cpf

import (
"errors"
"fmt"
"math/rand"
"strings"
"time"
)

// GenerateCPF generates a valid CPF number.
// If formatted is true, the CPF will be returned in the format xxx.xxx.xxx-xx.
// If formatted is false, the CPF will be returned as a plain string of 11 digits.
func GenerateCPF(formatted bool) (string, error) {
// Create a local random generator with a unique seed
src := rand.NewSource(time.Now().UnixNano())
r := rand.New(src)

// Generate the first 9 digits
digits := make([]int, 9)
for i := range digits {
digits[i] = r.Intn(10)
}

// Calculate the first check digit
digits = append(digits, calculateCheckDigit(digits, 10))

// Calculate the second check digit
digits = append(digits, calculateCheckDigit(digits, 11))

// Convert the digits to a string
cpf := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(digits)), ""), "[]")

// Format the CPF if requested
if formatted {
if len(cpf) != 11 {
return "", errors.New(ErrInvalidCPF.Error())
}
return cpf[:3] + "." + cpf[3:6] + "." + cpf[6:9] + "-" + cpf[9:], nil
}

return cpf, nil
}

// calculateCheckDigit calculates the check digit for a CPF.
func calculateCheckDigit(digits []int, weight int) int {
sum := 0
for _, digit := range digits {
sum += digit * weight
weight--
}

remainder := sum % 11
if remainder < 2 {
return 0
}
return 11 - remainder
}
51 changes: 51 additions & 0 deletions pkg/mocai/entities/cpf/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package cpf

import (
"strconv"
"strings"
)

// ValidateCPF checks if a CPF is valid.
// It accepts both formatted (xxx.xxx.xxx-xx) and unformatted (xxxxxxxxxxx) CPFs.
func ValidateCPF(cpf string) bool {
// Remove formatting (dots and dashes)
cpf = strings.ReplaceAll(cpf, ".", "")
cpf = strings.ReplaceAll(cpf, "-", "")

// Check if the CPF has 11 digits
if len(cpf) != 11 {
return false
}

// Convert the CPF string to a slice of integers
digits := make([]int, 11)
for i, char := range cpf {
digit, err := strconv.Atoi(string(char))
if err != nil {
return false
}
digits[i] = digit
}

// Check if all digits are the same (invalid CPF)
allSame := true
for i := 1; i < len(digits); i++ {
if digits[i] != digits[0] {
allSame = false
break
}
}
if allSame {
return false
}

// Calculate the first check digit
firstCheckDigit := calculateCheckDigit(digits[:9], 10)
if firstCheckDigit != digits[9] {
return false
}

// Calculate the second check digit
secondCheckDigit := calculateCheckDigit(digits[:10], 11)
return secondCheckDigit != digits[10]
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Feb 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix the incorrect return statement logic.

The return statement is inverted. It currently returns true when the second check digit doesn't match, which is incorrect.

-	return secondCheckDigit != digits[10]
+	return secondCheckDigit == digits[10]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return secondCheckDigit != digits[10]
return secondCheckDigit == digits[10]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wellfernandes Thanks for fixing the CPF validator's return statement! 🎉


If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!

}
9 changes: 9 additions & 0 deletions pkg/mocai/entities/person/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"math/rand"
"strings"

"github.com/brazzcore/mocai/pkg/mocai/entities/cpf"
"github.com/brazzcore/mocai/pkg/mocai/entities/gender"
"github.com/brazzcore/mocai/pkg/mocai/translations"
)
Expand All @@ -17,6 +18,7 @@ type Person struct {
LastName string
Gender gender.Gender
Age int
CPF string
}

// GeneratePerson generates a mock person with random data.
Expand Down Expand Up @@ -49,6 +51,12 @@ func GeneratePerson() (*Person, error) {
return nil, err
}

// Generate a random CPF without a mask
cpf, err := cpf.GenerateCPF(false)
if err != nil {
return nil, err
}

// Validate required fields
if firstNameMale == "" || firstNameFemale == "" || lastName == "" {
return nil, fmt.Errorf("%s: missing required data (firstNameMale: %s, firstNameFemale: %s, lastName: %s)",
Expand All @@ -61,6 +69,7 @@ func GeneratePerson() (*Person, error) {
LastName: lastName,
Gender: gender,
Age: rand.Intn(80) + 18,
CPF: cpf,
}

return createdPerson, nil
Expand Down
Loading