Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8521520
feat: added birth certificate generator
wellfernandes Mar 16, 2025
689fc08
feat: added birth certificate errors
wellfernandes Mar 16, 2025
4cd19e1
feat: added birth certificate validator
wellfernandes Mar 16, 2025
90b84be
feat: added brazilian birth certificate example
wellfernandes Mar 16, 2025
944ff89
refactor: changed import reference name
wellfernandes Mar 16, 2025
f07cbf8
fix: fixed function to generate valid check digit
wellfernandes Mar 17, 2025
7c7d555
fix: fixed birth certificate validation func
wellfernandes Mar 17, 2025
39a47b8
fix: fixed comment on birth certificate errors
wellfernandes Mar 17, 2025
aea3e6e
docs: updated main readme
wellfernandes Mar 18, 2025
c6b6809
docs: updated main readme
wellfernandes Mar 18, 2025
71163aa
docs: updated readme in portuguese
wellfernandes Mar 18, 2025
21941a3
merge: merge branch 'develop' into feature/23-birth-certificate-mock-…
wellfernandes Mar 20, 2025
343485f
remove: folders deleted after restructuring packages
wellfernandes Mar 20, 2025
38cb2ef
refactor: restructured packages for birth certificate
wellfernandes Mar 20, 2025
08e1a8e
feat: added example for birth certificate
wellfernandes Mar 20, 2025
f94442f
refactor: added parameter to format company data
wellfernandes Mar 20, 2025
2ca2b8d
refactor: changed company error comment
wellfernandes Mar 20, 2025
ca76f5f
refactor: added parameter to format company data
wellfernandes Mar 20, 2025
c145019
fix: fixed unit test for company
wellfernandes Mar 20, 2025
fe5796f
refactor: removed useless prints
wellfernandes Mar 20, 2025
a82807c
remove: files changed for generalization
wellfernandes Mar 21, 2025
2cf5c79
feat: added certificate generator
wellfernandes Mar 21, 2025
5f9d28a
feat: added generation model for brazilian certificates
wellfernandes Mar 21, 2025
3566391
fix: changed error to a generic error
wellfernandes Mar 21, 2025
d7d0412
feat: added certificate errors
wellfernandes Mar 21, 2025
cdeb81e
feat: added certificate validator
wellfernandes Mar 21, 2025
0cfefc9
feat: added mock examples for certificates
wellfernandes Mar 21, 2025
11f03ca
docs: updated main readme
wellfernandes Mar 21, 2025
74d8055
docs: updated portuguese readme
wellfernandes Mar 21, 2025
dd1d8a8
docs: added comment the certificate generator
wellfernandes Mar 21, 2025
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
32 changes: 24 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,21 @@ Basic Usage
Import the library into your project and start generating mocks:

```
package main
package examples

import (
"fmt"

"github.com/brazzcore/mocai/pkg/mocai/constants"
"github.com/brazzcore/mocai/pkg/mocai/entities/address"
brazilian_birth_certificate "github.com/brazzcore/mocai/pkg/mocai/entities/birth_certificate/brazil"
brazilian_company "github.com/brazzcore/mocai/pkg/mocai/entities/company/brazil"
"github.com/brazzcore/mocai/pkg/mocai/entities/person"
"github.com/brazzcore/mocai/pkg/mocai/entities/phone"
"github.com/brazzcore/mocai/pkg/mocai/translations"
)

func main() {
// Set the language to pt-BR
func GenerateMockExample() {
// Set the language to pt-BR
translations.SetLanguage("ptbr")

// Generate mock data
Expand All @@ -70,18 +71,33 @@ func main() {
fmt.Print(err)
}

fmt.Printf("Person: %s %s, %s, %d years old\n",
person_mock.FirstNameMale, person_mock.LastName, person_mock.Gender, person_mock.Age)
company_mock, err := brazilian_company.GenerateCompany()
if err != nil {
fmt.Print(err)
return
}

birth_certificate_mock, err := brazilian_birth_certificate.GenerateBirthCertificate(false)
if err != nil {
fmt.Print(err)
return
}

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("Birth Certificate: %s\n", birth_certificate_mock.BirthCertificateNumber)

fmt.Printf("Company: %s, CNPJ: %s\n", company_mock.CompanyName, company_mock.CNPJ)

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)
}
```

### Examples
The ***examples*** folder contains samples of how to use the library. To run the examples, navigate to the folder and execute:
The ***examples*** folder contains samples of how to use the library. To run the examples, navigate to the root folder and execute:

```
go run main.go
Expand Down
81 changes: 60 additions & 21 deletions docs/localization/pt/README-PT.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ Uma biblioteca Go para geração de dados de teste, permitindo criar mocks de en
O nome Mocai é uma homenagem à iniciativa brasileira por trás da biblioteca. Ele surgiu da combinação de "mock" (termo em inglês para simulação ou dados fictícios) com "açaí", uma fruta típica da Amazônia brasileira, conhecida por sua energia e versatilidade. Assim como o açaí é essencial para muitos brasileiros, o Mocai busca ser uma ferramenta essencial para desenvolvedores que precisam de dados de teste eficientes e de qualidade. 🇧🇷

## 🛠️ Principais Recursos
- Geração de Dados Aleatórios: Crie mocks de entidades com dados variados e realistas.
- Consistência: Garanta que os dados gerados sejam consistentes e adequados para testes.
- Facilidade de Uso: Interface simples e intuitiva para integração rápida em seus projetos.
- Extensibilidade: Adicione novas entidades ou personalize as existentes conforme suas necessidades.
- Open Source: Colabore, sugira melhorias e contribua para o crescimento da biblioteca.
- **Geração de Dados Aleatórios:** Crie mocks de entidades com dados variados e realistas.
- **Consistência:** Garanta que os dados gerados sejam consistentes e adequados para testes.
- **Facilidade de Uso:** Interface simples e intuitiva para integração rápida em seus projetos.
- **Extensibilidade:** Adicione novas entidades ou personalize as existentes conforme suas necessidades.
- **Open Source:** Colabore, sugira melhorias e contribua para o crescimento da biblioteca.

## 🚀 Por que usar o Mocai?
- Produtividade: Reduza o tempo gasto na criação de dados de teste.
- Qualidade: Melhore a cobertura e a eficácia dos seus testes com dados realistas.
- Flexibilidade: Adapte os mocks às necessidades específicas do seu projeto.
- Comunidade: Faça parte de uma comunidade open-source que valoriza a colaboração e a inovação.
- **Produtividade:** Reduza o tempo gasto na criação de dados de teste.
- **Qualidade:** Melhore a cobertura e a eficácia dos seus testes com dados realistas.
- **Flexibilidade:** Adapte os mocks às necessidades específicas do seu projeto.
- **Comunidade:** Faça parte de uma comunidade open-source que valoriza a colaboração e a inovação.


## 🚀 Como Começar
Expand All @@ -36,29 +36,68 @@ Uso Básico
Importe a biblioteca em seu projeto e comece a gerar mocks:

```
package main
package examples

import (
"fmt"
"github.com/brazzcore/mocai/pkg/mocai"

"fmt"

"github.com/brazzcore/mocai/pkg/mocai/entities/address"
brazilian_birth_certificate "github.com/brazzcore/mocai/pkg/mocai/entities/birth_certificate/brazil"
brazilian_company "github.com/brazzcore/mocai/pkg/mocai/entities/company/brazil"
"github.com/brazzcore/mocai/pkg/mocai/entities/person"
"github.com/brazzcore/mocai/pkg/mocai/entities/phone"
"github.com/brazzcore/mocai/pkg/mocai/translations"
)

func main() {
// Gerar um mock em português (pt-br)
mock := mocai.GenerateMocai("pt-br")
func GenerateMockExample() {
// Defina o idioma para pt-BR
translations.SetLanguage("ptbr")

// Gerar dados mock
person_mock, err := person.GeneratePerson()
if err != nil {
fmt.Print(err)
}

address_mock, err := address.GenerateAddress()
if err != nil {
fmt.Print(err)
}

phone_mock, err := phone.GeneratePhone()
if err != nil {
fmt.Print(err)
}

company_mock, err := brazilian_company.GenerateCompany()
if err != nil {
fmt.Print(err)
return
}

birth_certificate_mock, err := brazilian_birth_certificate.GenerateBirthCertificate(false)
if err != nil {
fmt.Print(err)
return
}

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("Birth Certificate: %s\n", birth_certificate_mock.BirthCertificateNumber)

fmt.Printf("Company: %s, CNPJ: %s\n", company_mock.CompanyName, company_mock.CNPJ)

fmt.Println("Pessoa:", mock.Person.FirstName, mock.Person.LastName)
fmt.Println("Endereço:", mock.Address.Street, mock.Address.Number)
fmt.Println("Telefone:", mock.Phone.AreaCode, mock.Phone.Number)
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)
}
```

### Exemplos
A pasta ***examples*** contém exemplos de como usar a biblioteca. Para executar os exemplos, navegue até a pasta e execute:
A pasta ***examples*** contém exemplos de como usar a biblioteca. Para executar os exemplos, navegue até a pasta raiz e execute:

```
cd examples
go run main.go
```

Expand Down
13 changes: 11 additions & 2 deletions examples/mock_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/brazzcore/mocai/pkg/mocai/constants"
"github.com/brazzcore/mocai/pkg/mocai/entities/address"
"github.com/brazzcore/mocai/pkg/mocai/entities/birth_certificate"
"github.com/brazzcore/mocai/pkg/mocai/entities/company"
"github.com/brazzcore/mocai/pkg/mocai/entities/person"
"github.com/brazzcore/mocai/pkg/mocai/entities/phone"
Expand All @@ -31,9 +32,15 @@ func GenerateMockExample() {
fmt.Print(err)
}

company_mock, err := company.GenerateCompany()
company_mock, err := company.GenerateCompany(false)
if err != nil {
fmt.Println("Error generating company:", err)
fmt.Print(err)
return
}

birth_certificate_mock, err := birth_certificate.GenerateBirthCertificate(false)
if err != nil {
fmt.Print(err)
return
}

Expand All @@ -43,6 +50,8 @@ func GenerateMockExample() {
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("Birth Certificate: %s\n", birth_certificate_mock.BrazilianBirthCertificate.CertificateNumber)

fmt.Printf("Company: %s, CNPJ: %s\n", company_mock.BrazilianCompany.CompanyName, company_mock.BrazilianCompany.CNPJ)

fmt.Printf("Address: %s, %d - %s, %s (%s) - %s\n",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package countries

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

// BrazilianBirthCertificate represents the structure of a Brazilian birth certificate
// containing all its components and the final certificate number
type BrazilianBirthCertificate struct {
VitalRecordsOffice int
ArchiveCode int
ServiceType int
BirthYear int
CertificateType int
BookNumber int
PageNumber int
TermNumber int
CheckDigits string
CertificateNumber string
}

// GenerateBirthCertificate generates a valid Brazilian birth certificate number
// If formatted is true, returns the number with separators (-)
// Returns a pointer to BrazilianBirthCertificate and error if any validation fails
func GenerateBirthCertificate(formatted bool) (*BrazilianBirthCertificate, error) {

// Create a new random source
r := rand.New(rand.NewSource(time.Now().UnixNano()))

// Registry Office
// 1. Vital Records Office [6 digits]
vitalRecordsOffice := r.Intn(899999) + 100000
if vitalRecordsOffice < 0 {
return nil, ErrInvalidVitalRecordsOffice
}

// 2. Archive [2 digits]
archiveCode := 1

// 3. Civil Registry of Natural Persons [2 digits]
serviceType := 55

// 4. Birth Year [4 digits]
currentYear := time.Now().Year()
birthYear := r.Intn(currentYear-2010+1) + 2010

// 5. Certificate type [1 digit]
certificateType := 1

// 6. Book number [5 digits]
bookNumber := r.Intn(89999) + 10000
if bookNumber < 0 {
return nil, ErrInvalidBookNumber
}

// 7. Page number [3 digits]
pageNumber := r.Intn(899) + 100
if pageNumber < 0 {
return nil, ErrInvalidPageNumber
}

// 8. Term number [7 digits]
termNumber := r.Intn(8999999) + 1000000
if termNumber < 0 {
return nil, ErrInvalidTermNumber
}

// Number without check digits [30 digits]
numberWithoutCheckDigits := fmt.Sprintf("%06d%02d%02d%04d%d%05d%03d%07d",
vitalRecordsOffice, archiveCode, serviceType, birthYear, certificateType, bookNumber, pageNumber, termNumber)
if len(numberWithoutCheckDigits) != 30 {
print(numberWithoutCheckDigits)
return nil, ErrInvalidNumberWithoutCheckDigits
}

// 9. Check digits calculation [2 digits]
checkDigits := calculateCheckDigits(numberWithoutCheckDigits)
print("checkDigits: ", checkDigits)

certificateNumber := fmt.Sprintf("%s%02s", numberWithoutCheckDigits, checkDigits)
if formatted {
certificateNumber = fmt.Sprintf("%06d %02d %02d %04d %d %05d %03d %07d-%02s",
vitalRecordsOffice, archiveCode, serviceType, birthYear, certificateType, bookNumber, pageNumber, termNumber, checkDigits)
}

if certificateNumber == "" {
return nil, ErrInvalidBirthCertificate
}

brazilianCertificate := &BrazilianBirthCertificate{
VitalRecordsOffice: vitalRecordsOffice,
ArchiveCode: archiveCode,
ServiceType: serviceType,
BirthYear: birthYear,
CertificateType: certificateType,
BookNumber: bookNumber,
PageNumber: pageNumber,
TermNumber: termNumber,
CheckDigits: checkDigits,
CertificateNumber: certificateNumber,
}

return brazilianCertificate, nil
}

// calculateCheckDigits calculates the check digits for the birth certificate number
// using a weight-based algorithm / using Mod 11
func calculateCheckDigits(number string) string {
dv1Weights := [30]int{
9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
0, 10, 9, 8, 7, 6, 5, 4, 3, 2,
}

sumDV1 := 0
for i := 0; i < 30; i++ {
// reverse access: b1 = last digit [position 29], b30 = first [position 0]
digit := int(number[29-i] - '0')
sumDV1 += digit * dv1Weights[i]
}

dv1 := sumDV1 % 11
if dv1 == 10 {
dv1 = 1
}

dv2Weights := [31]int{
9, // first term: dv1 * 9
8, 7, 6, 5, 4, 3, 2, 1, 0,
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
0, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
}

sumDV2 := 0
// first term: dv1 * 9
sumDV2 += dv1 * dv2Weights[0]

// remaining terms: b1 to b30 with remaining weights
for i := 0; i < 30; i++ {
digit := int(number[29-i] - '0')
sumDV2 += digit * dv2Weights[i+1]
}

dv2 := sumDV2 % 11
if dv2 == 10 {
dv2 = 1
}

return fmt.Sprintf("%d%d", dv1, dv2)
}
18 changes: 18 additions & 0 deletions pkg/mocai/entities/birth_certificate/countries/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package countries

import "errors"

// Errors for Birth Certificate data generation failures.
// These errors represent specific failure scenarios and should be wrapped with additional
// context when returned.
var (
ErrInvalidBirthCertificate = errors.New("invalid birth certificate")
ErrInvalidVitalRecordsOffice = errors.New("invalid vital records office number")
ErrInvalidArchive = errors.New("invalid archive number")
ErrInvalidVitalRecordsService = errors.New("invalid vital records service number")
ErrInvalidBirthYear = errors.New("invalid birth year")
ErrInvalidBookNumber = errors.New("invalid book number")
ErrInvalidPageNumber = errors.New("invalid page number")
ErrInvalidTermNumber = errors.New("invalid term number")
ErrInvalidNumberWithoutCheckDigits = errors.New("invalid number without check digits")
)
Loading
Loading