Skip to content

[Feature/55] :: flexibility improvements#56

Merged
wellfernandes merged 36 commits intodevelopfrom
feature/55-flexibility-improvements
Mar 26, 2026
Merged

[Feature/55] :: flexibility improvements#56
wellfernandes merged 36 commits intodevelopfrom
feature/55-flexibility-improvements

Conversation

@wellfernandes
Copy link
Copy Markdown
Member

@wellfernandes wellfernandes commented Mar 26, 2026

  • refactoring to make mocaí more flexible and extensible

Summary by CodeRabbit

Release Notes

  • New Features

    • API de criação de mocks modernizada com opções funcionais (WithLanguage, WithFormatted, WithRandSource)
    • Suporte a provedores customizados para endereços, pessoas e empresas
    • Geração determinística de dados via configuração de fonte aleatória
  • Refactor

    • Melhor tratamento de erros com sentinelas específicas em todas as entidades
    • Interface MockGenerator para abstração de geração de dados
  • Documentation

    • READMEs atualizados (português e inglês) com exemplos de uso básico e avançado
  • Tests

    • Cobertura abrangente de testes unitários para todas as entidades

@wellfernandes wellfernandes requested a review from DODOSUBI March 26, 2026 02:47
@wellfernandes wellfernandes self-assigned this Mar 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

Walkthrough

Este pull request refatora a API principal da biblioteca mocai, substituindo parâmetros posicionais por padrão de opções funcionais no NewMocker, introduzindo a interface MockGenerator, adicionando variáveis sentinela de erro para melhor tratamento de erros em múltiplas entidades e expandindo significativamente a cobertura de testes.

Changes

Cohort / File(s) Summary
Documentação
README.md, docs/localization/pt/README-PT.md
Atualiza exemplos de uso básico para usar opções funcionais (WithLanguage, WithFormatted), adiciona seção "Uso Avançado" documentando MockGenerator, providers customizados e WithRandSource. Adiciona "Gênero" e remove "CNPJ" da lista de entidades suportadas.
Exemplo de Código
examples/mocker/main.go
Refatora NewMocker para usar opções funcionais, expande geração de múltiplas entidades com tratamento consistente de erros, adiciona função auxiliar printLanguage para demonstrar injeção de dependência.
Sentinelas de Erro — Endereço
pkg/mocai/entities/address/generator.go
Substitui SlicesToCheck exportado por slicesToCheck não-exportado, simplifica inicialização de RandSource quando nil para usar translations.DefaultRandSource() diretamente.
Sentinelas de Erro — Certificado
pkg/mocai/entities/certificate/countries/brazilian_certificates.go
Introduz variáveis sentinela exportadas (ErrInvalidCertificate, ErrInvalidVitalRecordsOffice, ErrInvalidBookNumber, etc.), refatora gerador de certificados para usar fmt.Errorf com %w, simplifica retornos com literais compostos.
Sentinelas de Erro — CNPJ
pkg/mocai/entities/cnpj/generator.go
Adiciona sentinela ErrInvalidCNPJLength, substitui parâmetro interface{ Intn(n int) int } por translations.RandSource, remove dependência direta de math/rand/time.
Sentinelas de Erro — Empresa
pkg/mocai/entities/company/countries/brazilian_company.go
Introduz sentinelas ErrNoCompanyNames, ErrGeneratingCompany, ErrInvalidCompanyCNPJ, envolve mensagens de erro com fmt.Errorf("%w: ..."), simplifica retorno removendo variável intermediária.
Sentinelas de Erro — CPF
pkg/mocai/entities/cpf/generator.go
Adiciona sentinela ErrInvalidCPF, atualiza NewCPF para envolver erros de validação de comprimento com sentinela via %w.
Sentinelas de Erro — Gênero
pkg/mocai/entities/gender/gender.go
Introduz sentinela ErrNoGenderData, envolve erros de falta de dados com sentinela enquanto preserva mensagem traduzida.
Sentinelas de Erro — Pessoa
pkg/mocai/entities/person/generator.go
Adiciona sentinelas ErrNoFirstNames, ErrNoLastNames, ErrGeneratingPerson, atualiza caminhos de falha para envolver mensagens traduzidas com sentinelas.
Sentinelas de Erro — Telefone
pkg/mocai/entities/phone/generator.go
Introduz sentinelas ErrNoAreaCodes, ErrGeneratingPhone, envolve erros gerados com fmt.Errorf("%w: ...).
Sentinelas de Erro — ID Nacional
pkg/mocai/entities/nationalid/countries/brazilian_national_id.go
Adiciona sentinela ErrConvertingDigit, altera assinatura de NewRGCustom para retornar (RG, error), remove parâmetro variádico lang ...string, adiciona comportamento de default para "ptbr".
Sentinelas de Erro — Registro de Voto
pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration.go
Introduz sentinelas ErrInvalidVoteRegistration, ErrInvalidCheckDigit1, ErrInvalidCheckDigit2, envolve erros de validação com sentinelas usando %w.
Simplificação — Registro de Voto
pkg/mocai/entities/voteregistration/generator.go
Retorna diretamente resultado de generateVoteRegistration ao invés de atribuição intermediária, atualiza documentação com pontuação consistente.
Testes — Endereço
pkg/mocai/entities/address/generator_test.go
Novo arquivo de teste com três casos cobrindo geração básica, fallback de idioma não-suportado e múltiplas iterações.
Testes — Certificado, CNPJ, Empresa, CPF, Gênero, Pessoa, Telefone, ID Nacional, Registro de Voto
pkg/mocai/entities/*/..._test.go
Novos arquivos de teste cobrindo geração bem-sucedida, comportamento com idiomas não-suportados, validação de comprimento formatado, verificação de sentinelas com errors.Is, e testes de stress com múltiplas iterações.
API Principal — MockGenerator e Opções
pkg/mocai/mocker.go, pkg/mocai/options.go, pkg/mocai/provider.go
Introduz interface MockGenerator com 10 métodos, refatora NewMocker(opts ...Option) MockGenerator com opções funcionais (WithLanguage, WithFormatted, WithRandSource, WithAddressProvider, WithPersonProvider, WithCompanyProvider), renomeia GetLanguage() para Language(), adiciona delegação condicional para providers injetados.
Testes — Mocker Principal
pkg/mocai/mocker_test.go
Novo arquivo com 157 linhas testando configuração padrão, opções funcionais, conformidade com interface MockGenerator, múltiplas factories com RandSource customizado.
Tradução
pkg/mocai/translations/en_us.go, pkg/mocai/translations/pt_br.go, pkg/mocai/translations/safe_rand.go, pkg/mocai/translations/translations.go
Remove math/rand de pt_br.go, corrige chave invalid_vital_records_service_number, adiciona entradas para erros de voto registration, altera DefaultRandSource() para usar math/rand/v2 global via novo tipo globalRand, atualiza comentários de doc-string em translations.go.
Testes — Tradução
pkg/mocai/translations/translations_test.go
Novo arquivo com 224 linhas cobrindo registro/recuperação, fallback de idioma, listas, seleção aleatória determinista, GetUFMap, e concorrência.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutos

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • DODOSUBI
  • rluders
  • BertBR

Poem

🐰 Coelhos e opções funcionais,
Refatorando com elegância formal,
Sentinelas de erro por toda parte,
MockGenerator é a melhor arte,
Testes crescem, código mais legal! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive O título é vago e genérico, utilizando o termo "flexibility improvements" sem especificar claramente qual é a principal mudança no changeset. Considere usar um título mais descritivo e específico, como "Introduce functional options API and provider interfaces for flexible mock generation" ou "Refactor mocker to use options pattern for improved extensibility".
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/55-flexibility-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration.go (1)

82-94: ⚠️ Potential issue | 🟠 Major

O fallback de idioma está inconsistente com a API pública.

NewBrazilianVoteRegistration() fixa ptbr, mas NewBrazilianVoteRegistrationCustom() cai para en_us quando lang == "" ou quando o idioma não é suportado. Isso faz o comportamento mudar só pela escolha do entrypoint e pode devolver chaves cruas de tradução.

💡 Ajuste sugerido
 func NewBrazilianVoteRegistrationCustom(lang string, isFormatted bool, rnd translations.RandSource) (*BrazilianVoteRegistration, error) {
 	if lang == "" {
-		lang = "en_us"
+		lang = "ptbr"
 	}
@@
 	if !supported {
-		lang = "en_us"
+		lang = "ptbr"
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration.go`
around lines 82 - 94, The language fallback in
NewBrazilianVoteRegistrationCustom is inconsistent with
NewBrazilianVoteRegistration (which uses "ptbr"); change
NewBrazilianVoteRegistrationCustom so that when lang == "" or when the
translations check for "invalid_vote_registration" indicates unsupported, it
falls back to "ptbr" (not "en_us"), keeping the same behavior as
NewBrazilianVoteRegistration and avoiding returning raw translation keys; update
the lang default and unsupported-path assignment accordingly while preserving
the translations.Get(...) check and rnd/isFormatted handling.
🧹 Nitpick comments (9)
pkg/mocai/entities/phone/generator.go (1)

27-44: Verificação de areaCode vazio pode ser redundante ou insuficiente.

A verificação em if areaCode == "" na linha 38 ocorre após selecionar um elemento da slice areaCodes. Se a slice contém strings vazias, este check falha corretamente. Porém, como já existe uma verificação len(areaCodes) == 0 na linha 29, considere se a validação de strings vazias dentro da slice deveria ser feita de forma consistente com outros geradores (como address/generator.go que valida TrimSpace em cada item).

♻️ Sugestão para validação consistente
 func generatePhone(lang string, rnd translations.RandSource) (*Phone, error) {
 	areaCodes := translations.GetList(lang, "phone_area_code")
 	if len(areaCodes) == 0 {
 		return nil, fmt.Errorf("%w: %s", ErrNoAreaCodes, translations.Get(lang, "no_data_available_for_area_codes"))
 	}
+	for _, code := range areaCodes {
+		if strings.TrimSpace(code) == "" {
+			return nil, fmt.Errorf("%w: empty area code in list", ErrNoAreaCodes)
+		}
+	}
 	if rnd == nil {
 		rnd = translations.DefaultRandSource()
 	}
 
 	areaCode := areaCodes[rnd.Intn(len(areaCodes))]
 	number := fmt.Sprintf("9%08d", rnd.Intn(100000000))
-	if areaCode == "" {
-		return nil, fmt.Errorf("%w: %s", ErrGeneratingPhone, translations.Get(lang, "error_generating_phone"))
-	}
 	return &Phone{
 		AreaCode: areaCode,
 		Number:   number,
 	}, nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/phone/generator.go` around lines 27 - 44, In
generatePhone, ensure areaCodes from translations.GetList(lang,
"phone_area_code") are validated for non-empty (trimmed) entries like other
generators: filter the areaCodes slice to remove strings where
strings.TrimSpace(item) == "" before checking length, return ErrNoAreaCodes with
the existing translations.Get message if the filtered slice is empty, then
select areaCode using rnd.Intn on the filtered slice; remove the redundant
post-selection empty check (or keep it only as a defensive panic) and keep
returning ErrGeneratingPhone using translations.Get(lang,
"error_generating_phone") only when generation truly fails.
pkg/mocai/entities/nationalid/countries/brazilian_national_id_test.go (1)

57-62: Teste TestRGErrorIsSentinel não testa um cenário real de erro.

O teste apenas verifica que errors.Is(ErrConvertingDigit, ErrConvertingDigit) retorna true, o que é sempre verdade por definição. Um teste mais útil seria provocar uma condição de erro real e verificar se o erro retornado é o sentinela esperado.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/nationalid/countries/brazilian_national_id_test.go` around
lines 57 - 62, The test TestRGErrorIsSentinel currently only compares
ErrConvertingDigit to itself; instead produce a real wrapped error and assert
errors.Is identifies the sentinel: create an error that wraps ErrConvertingDigit
(e.g., via fmt.Errorf("failed converting digit: %w", ErrConvertingDigit) or
using errors.Join/wrap from the codebase) and replace the current assertion with
errors.Is(wrappedErr, ErrConvertingDigit); reference the test name
TestRGErrorIsSentinel and the sentinel ErrConvertingDigit when making the
change.
pkg/mocai/entities/certificate/countries/brazilian_certificates_test.go (1)

50-67: Considere usar constantes exportadas para tipos de certidão.

O teste verifica valores literais (1, 2, 3) para tipos de certidão. Se essas constantes forem exportadas no futuro, usar as constantes ao invés de valores literais tornaria os testes mais resilientes a mudanças.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/certificate/countries/brazilian_certificates_test.go`
around lines 50 - 67, Replace the literal type checks in TestCertificateTypes
with the exported certificate type constants instead of numbers: update the
assertions that inspect certs.BirthCertificate.Type,
certs.MarriageCertificate.Type and certs.DeathCertificate.Type (produced by
NewBrazilCertificatesCustom) to compare against the package's exported constants
(e.g., BirthCertificateType, MarriageCertificateType, DeathCertificateType or
whichever exported names exist) and adjust imports if necessary so the test uses
those constants rather than 1, 2, 3.
pkg/mocai/entities/cnpj/generator_test.go (1)

70-88: Extrair fixedRand para um pacote de test helpers.

O helper fixedRand (versão de sequência) é duplicado identicamente em pkg/mocai/entities/cpf/generator_test.go. Considere centralizá-lo em um pacote testutil dentro de internal/ para evitar duplicação de código.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/cnpj/generator_test.go` around lines 70 - 88, The
duplicated test helper fixedRand (type fixedRand with method Intn) should be
extracted into a shared internal testutil package: create an internal/testutil
package exposing a fixedRand (or NewFixedRand) constructor and the same Intn
behavior, move the implementation there, and update both generator_test.go files
to import testutil and instantiate the helper from that package instead of
duplicating the code; ensure the exported symbol names match usage and run tests
to verify behavior remains identical.
pkg/mocai/entities/cpf/generator_test.go (1)

74-79: O teste de erro sentinela é trivial e não valida o wrapping real.

O teste errors.Is(ErrInvalidCPF, ErrInvalidCPF) sempre retornará true para qualquer valor de erro. Para validar corretamente o padrão de sentinel error com wrapping (%w), considere testar um cenário onde o erro é retornado pela função NewCPF e verificar se errors.Is(wrappedErr, ErrInvalidCPF) funciona.

♻️ Sugestão para teste mais significativo
 func TestCPFErrorIsSentinel(t *testing.T) {
-	err := ErrInvalidCPF
-	if !errors.Is(err, ErrInvalidCPF) {
-		t.Error("expected ErrInvalidCPF to match with errors.Is")
+	// Verifica que o erro sentinela é compatível com errors.Is
+	wrappedErr := fmt.Errorf("%w: contexto adicional", ErrInvalidCPF)
+	if !errors.Is(wrappedErr, ErrInvalidCPF) {
+		t.Error("expected wrapped error to match ErrInvalidCPF with errors.Is")
 	}
 }

Isso requer adicionar "fmt" aos imports.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/cpf/generator_test.go` around lines 74 - 79, Replace the
trivial self-comparison in TestCPFErrorIsSentinel with a wrapped-error scenario:
call NewCPF with invalid input to obtain the error (or wrap ErrInvalidCPF via
fmt.Errorf("%w", ErrInvalidCPF)) and then assert errors.Is(wrappedErr,
ErrInvalidCPF) returns true; update TestCPFErrorIsSentinel to use the function
that produces the error (NewCPF) and add the "fmt" import if you choose manual
wrapping with fmt.Errorf.
pkg/mocai/entities/cnpj/generator.go (1)

41-43: Inconsistência no padrão de erro comparado ao CPF.

Na linha 42, ErrInvalidCNPJLength é retornado diretamente, enquanto em cpf/generator.go (linha 41), o erro é wrapped com uma mensagem localizada: fmt.Errorf("%w: %s", ErrInvalidCPF, translations.Get(lang, "invalid_cpf")).

Para manter consistência no tratamento de erros e permitir mensagens localizadas, considere seguir o mesmo padrão.

♻️ Sugestão para consistência

A função GenerateCNPJ não recebe o parâmetro lang, então seria necessário adicioná-lo para suportar mensagens localizadas, ou aceitar o erro não-localizado como design intencional para esta função.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/cnpj/generator.go` around lines 41 - 43, The CNPJ
generator returns ErrInvalidCNPJLength directly, causing inconsistency with CPF
which wraps errors with localized messages; update GenerateCNPJ to accept a lang
parameter (matching cpf/generator.go pattern) and when len(cnpj) != 14 return a
wrapped error like fmt.Errorf("%w: %s", ErrInvalidCNPJ, translations.Get(lang,
"invalid_cnpj")); ensure you reference ErrInvalidCNPJLength (or replace it with
ErrInvalidCNPJ) and use translations.Get(lang, "invalid_cnpj") so error handling
mirrors the CPF implementation (see GenerateCPF/ErrInvalidCPF usage).
pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration_test.go (1)

53-65: Os testes de erro sentinela são triviais.

Assim como observado em cpf/generator_test.go, os testes errors.Is(ErrX, ErrX) sempre retornam true. Para validação mais significativa, considere testar cenários onde os erros são realmente retornados pelas funções de geração ou testar o wrapping com fmt.Errorf("%w", ...).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration_test.go`
around lines 53 - 65, The current TestVoteRegistrationErrorIsSentinel trivially
compares each sentinel to itself; replace it with real error-origin tests: call
the functions that can return these errors (e.g., the vote
registration/validation/generation functions used elsewhere) and assert
errors.Is(returnedErr, ErrInvalidVoteRegistration / ErrInvalidCheckDigit1 /
ErrInvalidCheckDigit2); alternatively create a wrapped error with
fmt.Errorf("%w", ErrInvalidCheckDigit1) and assert errors.Is on that wrapped
error to verify sentinel matching (see cpf/generator_test.go for a pattern).
pkg/mocai/mocker.go (2)

71-72: O caminho via provider perde o RandSource da instância.

WithRandSource só atualiza m.rnd em pkg/mocai/options.go:5-30, mas GeneratePerson, GenerateCompany e GenerateAddress em pkg/mocai/provider.go:9-26 não recebem esse valor. Se a intenção é manter determinismo por instância, o source precisa entrar nas interfaces — ou isso precisa ficar explícito na documentação do provider.

Also applies to: 85-86, 104-105

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/mocker.go` around lines 71 - 72, The provider path is losing the
instance RandSource because WithRandSource only sets m.rnd but provider methods
GeneratePerson/GenerateCompany/GenerateAddress on
personProvider/companyProvider/addressProvider don't accept it; update the
provider interfaces to accept a RandSource (or add a SetRandSource method) and
propagate m.rnd into calls from the methods in the Mocker (where you call
personProvider.GeneratePerson, companyProvider.GenerateCompany,
addressProvider.GenerateAddress), or alternatively pass m.rnd into those
Generate* calls so the providers use the instance RNG; ensure symbols
WithRandSource, m.rnd, GeneratePerson, GenerateCompany, GenerateAddress,
personProvider, companyProvider and addressProvider are updated consistently.

56-66: Prefira retornar *Mocker e deixar a interface no lado do consumo.

Em Go, NewX retornando interface costuma limitar a evolução da API pública sem ganho real. Quem quiser abstração ainda pode fazer var g MockGenerator = NewMocker(...).

💡 Ajuste sugerido
-func NewMocker(opts ...Option) MockGenerator {
+func NewMocker(opts ...Option) *Mocker {
 	m := &Mocker{
 		lang:      "ptbr",
 		formatted: false,
 		rnd:       translations.DefaultRandSource(),
 	}
 	for _, opt := range opts {
 		opt(m)
 	}
 	return m
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/mocker.go` around lines 56 - 66, Change NewMocker to return *Mocker
instead of the MockGenerator interface: update the function signature
NewMocker(opts ...Option) *Mocker and keep the constructor body as-is (it
already constructs &Mocker). Ensure all Option functions and their types (those
accepting m *Mocker) remain compatible, and update any call sites or tests that
expect a MockGenerator to accept the concrete *Mocker (callers that need the
interface can still assign var g MockGenerator = NewMocker(...)). Leave the
MockGenerator interface declared but remove it from the public constructor
return type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/localization/pt/README-PT.md`:
- Around line 5-6: The heading "#### [README (English)](/README.md)" is using h4
but should be h2 to preserve hierarchical order; update that Markdown heading
from "#### [README (English)](/README.md)" to "## [README
(English)](/README.md)" so it increments correctly from the document h1 to h2
and satisfies markdownlint/accessibility rules.

In `@pkg/mocai/entities/address/generator_test.go`:
- Around line 33-35: The test asserts Number must be positive but the generator
uses rnd.Intn(9999) (in generator.go) which can produce 0, so either relax the
test or fix the generator: if 0 is acceptable, change the test in
generator_test.go to assert addr.Number >= 0 (or remove the failing check); if 0
is not acceptable, change the generator's expression rnd.Intn(9999) to
rnd.Intn(9999) + 1 (in the function that creates addresses) so Number is always
> 0 and keep the existing test.

In `@pkg/mocai/entities/nationalid/countries/brazilian_national_id_test.go`:
- Around line 49-55: Rename the misleading test function TestRGReturnsError to a
name that reflects it expects no error (e.g., TestRGReturnsNoError or
TestRGSuccessfulGeneration); locate the test function declaration for
TestRGReturnsError in the file (which calls NewRGCustom("ptbr", false, nil) and
asserts err == nil) and rename the function identifier accordingly, and update
any references or test filters that may rely on the old name so the test suite
still runs.

In `@pkg/mocai/entities/nationalid/countries/brazilian_national_id.go`:
- Around line 21-31: The public API for NewRGCustom was changed (parameter order
and added error return), breaking consumers; revert NewRGCustom to its original
exported signature and semantics (original parameter order and single RG return)
and keep the new error-returning variant under a new symbol (e.g., NewRGCustomE
or NewRGCustomWithError) that calls generateBrazilianNationalIDCustom; ensure
generateBrazilianNationalIDCustom remains used by the new error-returning
wrapper while the restored NewRGCustom delegates to it and handles errors
internally so existing callers compile.

In `@pkg/mocai/mocker.go`:
- Around line 62-63: O loop que aplica opções pode executar um Option nil e
causar panic; dentro da função que aplica opts (onde a variável opts e o tipo
Option func(*Mocker) e a struct Mocker são usados), verifique cada opt por nil
antes de chamá-la (por exemplo: if opt == nil { continue }) ou filtre opções
nulas antes do loop, garantindo que apenas opções não-nulas sejam invocadas.

In `@pkg/mocai/options.go`:
- Around line 8-13: The WithLanguage option currently writes an empty string
into m.lang which overrides the default and causes inconsistent behavior; update
WithLanguage(func WithLanguage(lang string) Option) so it treats an empty lang
as a no-op (i.e., do not set m.lang when lang == "") or alternatively normalize
empty to the default "ptbr"; locate the Option closure in WithLanguage and add a
guard checking lang == "" and either return early without modifying m.lang or
set m.lang = "ptbr" to preserve the intended default for Mocker.

In `@pkg/mocai/translations/translations_test.go`:
- Around line 49-54: O teste deve parar imediatamente se GetList("test_lang",
"colors") devolver menos de 3 itens para evitar panics ao acessar val[0],
val[1], val[2]; substitua o t.Errorf de verificação de tamanho por t.Fatalf (por
exemplo na verificação em torno de len(val) != 3) para falhar fatalmente e
mantenha a verificação de conteúdo (os comparadores que usam
val[0]/val[1]/val[2]) após essa checagem segura; referências: função GetList e
as asserções no arquivo translations_test.go.
- Around line 132-146: The test TestGetUFMapReturnsDefensiveCopy is flaky
because it can pass when ufMap1 or ufMap2 is nil/empty and it checks a random
key; update the test to assert both GetUFMap("ptbr") results are non-nil and
non-empty, pick a concrete key from ufMap1 (e.g., first key via explicit
iteration), save its original value, modify that specific key in ufMap1, then
assert that ufMap2 still contains the original value for that same key;
reference GetUFMap and TestGetUFMapReturnsDefensiveCopy when making these
changes.
- Around line 98-102: The test currently passes nil which checks the "missing
list" case but not an actually empty slice; update
TestGetRandomReturnsKeyWhenListEmpty to also call GetRandom("nonexistent_lang",
"nonexistent_key", []string{}) (or replace the nil call with []string{}) and
assert the returned value is the key, ensuring GetRandom treats nil and
[]string{} the same; reference GetRandom and the test function name when making
the change.

In `@README.md`:
- Around line 22-31: A seção "## 📦 Supported Entities" removeu a menção ao
gerador de CNPJ standalone, gerando ambiguidade; atualize essa seção para
incluir explicitamente "CNPJ (standalone)" ou ajustar a linha "Company (name,
CNPJ)" para deixar claro que existe também um gerador direto de CNPJ na API
pública; revise o bloco de entidades (o título "Supported Entities" e as linhas
"Company" e "CNPJ") e reintroduza ou clarifique a entrada para CNPJ para
refletir a implementação atual.

---

Outside diff comments:
In
`@pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration.go`:
- Around line 82-94: The language fallback in NewBrazilianVoteRegistrationCustom
is inconsistent with NewBrazilianVoteRegistration (which uses "ptbr"); change
NewBrazilianVoteRegistrationCustom so that when lang == "" or when the
translations check for "invalid_vote_registration" indicates unsupported, it
falls back to "ptbr" (not "en_us"), keeping the same behavior as
NewBrazilianVoteRegistration and avoiding returning raw translation keys; update
the lang default and unsupported-path assignment accordingly while preserving
the translations.Get(...) check and rnd/isFormatted handling.

---

Nitpick comments:
In `@pkg/mocai/entities/certificate/countries/brazilian_certificates_test.go`:
- Around line 50-67: Replace the literal type checks in TestCertificateTypes
with the exported certificate type constants instead of numbers: update the
assertions that inspect certs.BirthCertificate.Type,
certs.MarriageCertificate.Type and certs.DeathCertificate.Type (produced by
NewBrazilCertificatesCustom) to compare against the package's exported constants
(e.g., BirthCertificateType, MarriageCertificateType, DeathCertificateType or
whichever exported names exist) and adjust imports if necessary so the test uses
those constants rather than 1, 2, 3.

In `@pkg/mocai/entities/cnpj/generator_test.go`:
- Around line 70-88: The duplicated test helper fixedRand (type fixedRand with
method Intn) should be extracted into a shared internal testutil package: create
an internal/testutil package exposing a fixedRand (or NewFixedRand) constructor
and the same Intn behavior, move the implementation there, and update both
generator_test.go files to import testutil and instantiate the helper from that
package instead of duplicating the code; ensure the exported symbol names match
usage and run tests to verify behavior remains identical.

In `@pkg/mocai/entities/cnpj/generator.go`:
- Around line 41-43: The CNPJ generator returns ErrInvalidCNPJLength directly,
causing inconsistency with CPF which wraps errors with localized messages;
update GenerateCNPJ to accept a lang parameter (matching cpf/generator.go
pattern) and when len(cnpj) != 14 return a wrapped error like fmt.Errorf("%w:
%s", ErrInvalidCNPJ, translations.Get(lang, "invalid_cnpj")); ensure you
reference ErrInvalidCNPJLength (or replace it with ErrInvalidCNPJ) and use
translations.Get(lang, "invalid_cnpj") so error handling mirrors the CPF
implementation (see GenerateCPF/ErrInvalidCPF usage).

In `@pkg/mocai/entities/cpf/generator_test.go`:
- Around line 74-79: Replace the trivial self-comparison in
TestCPFErrorIsSentinel with a wrapped-error scenario: call NewCPF with invalid
input to obtain the error (or wrap ErrInvalidCPF via fmt.Errorf("%w",
ErrInvalidCPF)) and then assert errors.Is(wrappedErr, ErrInvalidCPF) returns
true; update TestCPFErrorIsSentinel to use the function that produces the error
(NewCPF) and add the "fmt" import if you choose manual wrapping with fmt.Errorf.

In `@pkg/mocai/entities/nationalid/countries/brazilian_national_id_test.go`:
- Around line 57-62: The test TestRGErrorIsSentinel currently only compares
ErrConvertingDigit to itself; instead produce a real wrapped error and assert
errors.Is identifies the sentinel: create an error that wraps ErrConvertingDigit
(e.g., via fmt.Errorf("failed converting digit: %w", ErrConvertingDigit) or
using errors.Join/wrap from the codebase) and replace the current assertion with
errors.Is(wrappedErr, ErrConvertingDigit); reference the test name
TestRGErrorIsSentinel and the sentinel ErrConvertingDigit when making the
change.

In `@pkg/mocai/entities/phone/generator.go`:
- Around line 27-44: In generatePhone, ensure areaCodes from
translations.GetList(lang, "phone_area_code") are validated for non-empty
(trimmed) entries like other generators: filter the areaCodes slice to remove
strings where strings.TrimSpace(item) == "" before checking length, return
ErrNoAreaCodes with the existing translations.Get message if the filtered slice
is empty, then select areaCode using rnd.Intn on the filtered slice; remove the
redundant post-selection empty check (or keep it only as a defensive panic) and
keep returning ErrGeneratingPhone using translations.Get(lang,
"error_generating_phone") only when generation truly fails.

In
`@pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration_test.go`:
- Around line 53-65: The current TestVoteRegistrationErrorIsSentinel trivially
compares each sentinel to itself; replace it with real error-origin tests: call
the functions that can return these errors (e.g., the vote
registration/validation/generation functions used elsewhere) and assert
errors.Is(returnedErr, ErrInvalidVoteRegistration / ErrInvalidCheckDigit1 /
ErrInvalidCheckDigit2); alternatively create a wrapped error with
fmt.Errorf("%w", ErrInvalidCheckDigit1) and assert errors.Is on that wrapped
error to verify sentinel matching (see cpf/generator_test.go for a pattern).

In `@pkg/mocai/mocker.go`:
- Around line 71-72: The provider path is losing the instance RandSource because
WithRandSource only sets m.rnd but provider methods
GeneratePerson/GenerateCompany/GenerateAddress on
personProvider/companyProvider/addressProvider don't accept it; update the
provider interfaces to accept a RandSource (or add a SetRandSource method) and
propagate m.rnd into calls from the methods in the Mocker (where you call
personProvider.GeneratePerson, companyProvider.GenerateCompany,
addressProvider.GenerateAddress), or alternatively pass m.rnd into those
Generate* calls so the providers use the instance RNG; ensure symbols
WithRandSource, m.rnd, GeneratePerson, GenerateCompany, GenerateAddress,
personProvider, companyProvider and addressProvider are updated consistently.
- Around line 56-66: Change NewMocker to return *Mocker instead of the
MockGenerator interface: update the function signature NewMocker(opts ...Option)
*Mocker and keep the constructor body as-is (it already constructs &Mocker).
Ensure all Option functions and their types (those accepting m *Mocker) remain
compatible, and update any call sites or tests that expect a MockGenerator to
accept the concrete *Mocker (callers that need the interface can still assign
var g MockGenerator = NewMocker(...)). Leave the MockGenerator interface
declared but remove it from the public constructor return type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8fa23dec-fd47-4c5f-9284-7036c8ceb9cd

📥 Commits

Reviewing files that changed from the base of the PR and between 65f9e9a and 3e56b39.

📒 Files selected for processing (34)
  • README.md
  • docs/localization/pt/README-PT.md
  • examples/mocker/main.go
  • pkg/mocai/entities/address/generator.go
  • pkg/mocai/entities/address/generator_test.go
  • pkg/mocai/entities/certificate/countries/brazilian_certificates.go
  • pkg/mocai/entities/certificate/countries/brazilian_certificates_test.go
  • pkg/mocai/entities/cnpj/generator.go
  • pkg/mocai/entities/cnpj/generator_test.go
  • pkg/mocai/entities/company/countries/brazilian_company.go
  • pkg/mocai/entities/company/countries/generator_test.go
  • pkg/mocai/entities/cpf/generator.go
  • pkg/mocai/entities/cpf/generator_test.go
  • pkg/mocai/entities/gender/gender.go
  • pkg/mocai/entities/gender/gender_test.go
  • pkg/mocai/entities/nationalid/countries/brazilian_national_id.go
  • pkg/mocai/entities/nationalid/countries/brazilian_national_id_test.go
  • pkg/mocai/entities/nationalid/generator.go
  • pkg/mocai/entities/person/generator.go
  • pkg/mocai/entities/person/generator_test.go
  • pkg/mocai/entities/phone/generator.go
  • pkg/mocai/entities/phone/generator_test.go
  • pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration.go
  • pkg/mocai/entities/voteregistration/countries/brazilian_vote_registration_test.go
  • pkg/mocai/entities/voteregistration/generator.go
  • pkg/mocai/mocker.go
  • pkg/mocai/mocker_test.go
  • pkg/mocai/options.go
  • pkg/mocai/provider.go
  • pkg/mocai/translations/en_us.go
  • pkg/mocai/translations/pt_br.go
  • pkg/mocai/translations/safe_rand.go
  • pkg/mocai/translations/translations.go
  • pkg/mocai/translations/translations_test.go

Comment on lines +5 to +6
#### [README (English)](/README.md)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Corrija o nível do heading para manter a hierarquia correta.

O static analysis (markdownlint) indica que o heading na linha 5 usa #### (h4), mas deveria seguir a hierarquia incrementando de h1 para h2. Isso melhora a acessibilidade e a estrutura do documento.

📝 Correção sugerida
-#### [README (English)](/README.md)
+## [README (English)](/README.md)
📝 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
#### [README (English)](/README.md)
## [README (English)](/README.md)
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 5-5: Heading levels should only increment by one level at a time
Expected: h2; Actual: h4

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/localization/pt/README-PT.md` around lines 5 - 6, The heading "####
[README (English)](/README.md)" is using h4 but should be h2 to preserve
hierarchical order; update that Markdown heading from "#### [README
(English)](/README.md)" to "## [README (English)](/README.md)" so it increments
correctly from the document h1 to h2 and satisfies markdownlint/accessibility
rules.

Comment on lines +33 to +35
if addr.Number <= 0 {
t.Errorf("Number should be positive, got %d", addr.Number)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Asserção de Number pode falhar incorretamente.

O teste verifica addr.Number <= 0, mas o gerador em generator.go linha 94 usa rnd.Intn(9999) que pode retornar 0. Isso significa que Number = 0 é um valor válido gerado pelo sistema, mas o teste falharia nesse caso.

🐛 Correção sugerida
-	if addr.Number <= 0 {
-		t.Errorf("Number should be positive, got %d", addr.Number)
+	if addr.Number < 0 {
+		t.Errorf("Number should be non-negative, got %d", addr.Number)
 	}

Alternativamente, se Number = 0 realmente não é desejado, o gerador deveria usar rnd.Intn(9999) + 1.

📝 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
if addr.Number <= 0 {
t.Errorf("Number should be positive, got %d", addr.Number)
}
if addr.Number < 0 {
t.Errorf("Number should be non-negative, got %d", addr.Number)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/address/generator_test.go` around lines 33 - 35, The test
asserts Number must be positive but the generator uses rnd.Intn(9999) (in
generator.go) which can produce 0, so either relax the test or fix the
generator: if 0 is acceptable, change the test in generator_test.go to assert
addr.Number >= 0 (or remove the failing check); if 0 is not acceptable, change
the generator's expression rnd.Intn(9999) to rnd.Intn(9999) + 1 (in the function
that creates addresses) so Number is always > 0 and keep the existing test.

Comment on lines +49 to +55
func TestRGReturnsError(t *testing.T) {
_, err := NewRGCustom("ptbr", false, nil)

if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Nome do teste TestRGReturnsError é enganoso.

O teste verifica que nenhum erro é retornado (linha 52-54), mas o nome sugere que testa um cenário de erro. Considere renomear para TestRGReturnsNoError ou TestRGSuccessfulGeneration.

💡 Sugestão de renomeação
-func TestRGReturnsError(t *testing.T) {
+func TestRGReturnsNoError(t *testing.T) {
 	_, err := NewRGCustom("ptbr", false, nil)
 
 	if err != nil {
 		t.Fatalf("unexpected error: %v", err)
 	}
 }
📝 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
func TestRGReturnsError(t *testing.T) {
_, err := NewRGCustom("ptbr", false, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
func TestRGReturnsNoError(t *testing.T) {
_, err := NewRGCustom("ptbr", false, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/nationalid/countries/brazilian_national_id_test.go` around
lines 49 - 55, Rename the misleading test function TestRGReturnsError to a name
that reflects it expects no error (e.g., TestRGReturnsNoError or
TestRGSuccessfulGeneration); locate the test function declaration for
TestRGReturnsError in the file (which calls NewRGCustom("ptbr", false, nil) and
asserts err == nil) and rename the function identifier accordingly, and update
any references or test filters that may rely on the old name so the test suite
still runs.

Comment on lines +21 to +31
// NewRGCustom generates a random RG (Brazilian Identity Card) using an injected random source and language.
// Returns an error if generation fails, instead of silently returning an empty RG.
func NewRGCustom(lang string, isFormatted bool, rnd translations.RandSource) (RG, error) {
if lang == "" {
lang = "ptbr"
}
rg, err := generateBrazilianNationalIDCustom(isFormatted, rnd, l)
rg, err := generateBrazilianNationalIDCustom(lang, isFormatted, rnd)
if err != nil {
return RG{}
return RG{}, err
}
return rg
return rg, nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Essa mudança quebra a API pública de NewRGCustom.

A assinatura exportada mudou a ordem dos parâmetros e passou a exigir error no retorno. Isso faz consumidores externos deixarem de compilar mesmo que o uso anterior ainda fosse válido. Se a quebra for intencional, isso precisa ser tratado como breaking change explícita; caso contrário, vale preservar a entrada antiga e introduzir um novo símbolo para a variante com erro.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/entities/nationalid/countries/brazilian_national_id.go` around
lines 21 - 31, The public API for NewRGCustom was changed (parameter order and
added error return), breaking consumers; revert NewRGCustom to its original
exported signature and semantics (original parameter order and single RG return)
and keep the new error-returning variant under a new symbol (e.g., NewRGCustomE
or NewRGCustomWithError) that calls generateBrazilianNationalIDCustom; ensure
generateBrazilianNationalIDCustom remains used by the new error-returning
wrapper while the restored NewRGCustom delegates to it and handles errors
internally so existing callers compile.

Comment on lines +62 to +63
for _, opt := range opts {
opt(m)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n pkg/mocai/mocker.go | head -80

Repository: brazzcore/mocai

Length of output: 3337


🏁 Script executed:

grep -n "type Option" pkg/mocai/mocker.go

Repository: brazzcore/mocai

Length of output: 41


🏁 Script executed:

rg "type Option" pkg/mocai/

Repository: brazzcore/mocai

Length of output: 105


🏁 Script executed:

cat -n pkg/mocai/options.go

Repository: brazzcore/mocai

Length of output: 1925


🏁 Script executed:

rg "NewMocker" --type go -A 3 -B 1 | head -60

Repository: brazzcore/mocai

Length of output: 2828


Adicione verificação de nil para evitar panic com Option nulo.

Option é um func(*Mocker); um item nil na slice faz opt(m) panic, que pode ocorrer facilmente em composição condicional de opções.

💡 Ajuste sugerido
 for _, opt := range opts {
-	opt(m)
+	if opt != nil {
+		opt(m)
+	}
 }
📝 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
for _, opt := range opts {
opt(m)
for _, opt := range opts {
if opt != nil {
opt(m)
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/mocker.go` around lines 62 - 63, O loop que aplica opções pode
executar um Option nil e causar panic; dentro da função que aplica opts (onde a
variável opts e o tipo Option func(*Mocker) e a struct Mocker são usados),
verifique cada opt por nil antes de chamá-la (por exemplo: if opt == nil {
continue }) ou filtre opções nulas antes do loop, garantindo que apenas opções
não-nulas sejam invocadas.

Comment on lines +8 to +13
// WithLanguage sets the language for mock data generation.
// Default: "ptbr"
func WithLanguage(lang string) Option {
return func(m *Mocker) {
m.lang = lang
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

WithLanguage("") anula o default em vez de preservá-lo.

Como essa opção grava a string vazia sem normalização, o Mocker entra em caminhos diferentes dependendo da entidade: algumas geram ptbr, outras caem em en_us e outras falham. Trate vazio como no-op ou normalize para ptbr.

💡 Ajuste sugerido
 func WithLanguage(lang string) Option {
 	return func(m *Mocker) {
-		m.lang = lang
+		if lang == "" {
+			return
+		}
+		m.lang = lang
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/options.go` around lines 8 - 13, The WithLanguage option currently
writes an empty string into m.lang which overrides the default and causes
inconsistent behavior; update WithLanguage(func WithLanguage(lang string)
Option) so it treats an empty lang as a no-op (i.e., do not set m.lang when lang
== "") or alternatively normalize empty to the default "ptbr"; locate the Option
closure in WithLanguage and add a guard checking lang == "" and either return
early without modifying m.lang or set m.lang = "ptbr" to preserve the intended
default for Mocker.

Comment on lines +49 to +54
val := GetList("test_lang", "colors")
if len(val) != 3 {
t.Errorf("expected 3 items, got %d", len(val))
}
if val[0] != "red" || val[1] != "green" || val[2] != "blue" {
t.Errorf("unexpected values: %v", val)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use Fatalf no cheque de tamanho.

Se GetList voltar menos de 3 itens, o teste segue e pode estourar índice em val[0], val[1] ou val[2], escondendo a causa real.

💡 Ajuste sugerido
 val := GetList("test_lang", "colors")
 if len(val) != 3 {
-	t.Errorf("expected 3 items, got %d", len(val))
+	t.Fatalf("expected 3 items, got %d", len(val))
 }
 if val[0] != "red" || val[1] != "green" || val[2] != "blue" {
 	t.Errorf("unexpected values: %v", val)
 }
📝 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
val := GetList("test_lang", "colors")
if len(val) != 3 {
t.Errorf("expected 3 items, got %d", len(val))
}
if val[0] != "red" || val[1] != "green" || val[2] != "blue" {
t.Errorf("unexpected values: %v", val)
val := GetList("test_lang", "colors")
if len(val) != 3 {
t.Fatalf("expected 3 items, got %d", len(val))
}
if val[0] != "red" || val[1] != "green" || val[2] != "blue" {
t.Errorf("unexpected values: %v", val)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/translations/translations_test.go` around lines 49 - 54, O teste
deve parar imediatamente se GetList("test_lang", "colors") devolver menos de 3
itens para evitar panics ao acessar val[0], val[1], val[2]; substitua o t.Errorf
de verificação de tamanho por t.Fatalf (por exemplo na verificação em torno de
len(val) != 3) para falhar fatalmente e mantenha a verificação de conteúdo (os
comparadores que usam val[0]/val[1]/val[2]) após essa checagem segura;
referências: função GetList e as asserções no arquivo translations_test.go.

Comment on lines +98 to +102
func TestGetRandomReturnsKeyWhenListEmpty(t *testing.T) {
val := GetRandom("nonexistent_lang", "nonexistent_key", nil)
if val != "nonexistent_key" {
t.Errorf("expected key returned as-is, got %q", val)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

O cenário aqui é “lista ausente”, não “lista vazia”.

Se GetRandom tratar nil e []string{} de forma diferente, a regressão passa neste teste. Vale registrar uma chave com slice vazio para cobrir o caso que o nome promete.

💡 Ajuste sugerido
 func TestGetRandomReturnsKeyWhenListEmpty(t *testing.T) {
-	val := GetRandom("nonexistent_lang", "nonexistent_key", nil)
-	if val != "nonexistent_key" {
+	RegisterList("empty_rand_lang", map[string][]string{
+		"empty_key": {},
+	})
+	val := GetRandom("empty_rand_lang", "empty_key", nil)
+	if val != "empty_key" {
 		t.Errorf("expected key returned as-is, got %q", val)
 	}
 }
📝 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
func TestGetRandomReturnsKeyWhenListEmpty(t *testing.T) {
val := GetRandom("nonexistent_lang", "nonexistent_key", nil)
if val != "nonexistent_key" {
t.Errorf("expected key returned as-is, got %q", val)
}
func TestGetRandomReturnsKeyWhenListEmpty(t *testing.T) {
RegisterList("empty_rand_lang", map[string][]string{
"empty_key": {},
})
val := GetRandom("empty_rand_lang", "empty_key", nil)
if val != "empty_key" {
t.Errorf("expected key returned as-is, got %q", val)
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/translations/translations_test.go` around lines 98 - 102, The test
currently passes nil which checks the "missing list" case but not an actually
empty slice; update TestGetRandomReturnsKeyWhenListEmpty to also call
GetRandom("nonexistent_lang", "nonexistent_key", []string{}) (or replace the nil
call with []string{}) and assert the returned value is the key, ensuring
GetRandom treats nil and []string{} the same; reference GetRandom and the test
function name when making the change.

Comment on lines +132 to +146
func TestGetUFMapReturnsDefensiveCopy(t *testing.T) {
ufMap1 := GetUFMap("ptbr")
ufMap2 := GetUFMap("ptbr")

for k := range ufMap1 {
ufMap1[k] = "MODIFIED"
break
}

for k, v := range ufMap2 {
if v == "MODIFIED" {
t.Errorf("GetUFMap returned a shared reference, key %q was modified", k)
}
break
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Esse teste de cópia defensiva pode passar em falso.

Hoje ele não falha se um dos mapas vier nil/vazio, e o segundo range valida uma chave aleatória — não necessariamente a mesma que foi alterada.

💡 Ajuste sugerido
 func TestGetUFMapReturnsDefensiveCopy(t *testing.T) {
 	ufMap1 := GetUFMap("ptbr")
 	ufMap2 := GetUFMap("ptbr")
+	if len(ufMap1) == 0 || len(ufMap2) == 0 {
+		t.Fatal("expected non-empty UF maps for ptbr")
+	}
 
+	var modifiedKey string
 	for k := range ufMap1 {
+		modifiedKey = k
 		ufMap1[k] = "MODIFIED"
 		break
 	}
+	if modifiedKey == "" {
+		t.Fatal("expected at least one key in UF map")
+	}
 
-	for k, v := range ufMap2 {
-		if v == "MODIFIED" {
-			t.Errorf("GetUFMap returned a shared reference, key %q was modified", k)
-		}
-		break
+	if ufMap2[modifiedKey] == "MODIFIED" {
+		t.Errorf("GetUFMap returned a shared reference, key %q was modified", modifiedKey)
 	}
 }
📝 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
func TestGetUFMapReturnsDefensiveCopy(t *testing.T) {
ufMap1 := GetUFMap("ptbr")
ufMap2 := GetUFMap("ptbr")
for k := range ufMap1 {
ufMap1[k] = "MODIFIED"
break
}
for k, v := range ufMap2 {
if v == "MODIFIED" {
t.Errorf("GetUFMap returned a shared reference, key %q was modified", k)
}
break
}
func TestGetUFMapReturnsDefensiveCopy(t *testing.T) {
ufMap1 := GetUFMap("ptbr")
ufMap2 := GetUFMap("ptbr")
if len(ufMap1) == 0 || len(ufMap2) == 0 {
t.Fatal("expected non-empty UF maps for ptbr")
}
var modifiedKey string
for k := range ufMap1 {
modifiedKey = k
ufMap1[k] = "MODIFIED"
break
}
if modifiedKey == "" {
t.Fatal("expected at least one key in UF map")
}
if ufMap2[modifiedKey] == "MODIFIED" {
t.Errorf("GetUFMap returned a shared reference, key %q was modified", modifiedKey)
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/mocai/translations/translations_test.go` around lines 132 - 146, The test
TestGetUFMapReturnsDefensiveCopy is flaky because it can pass when ufMap1 or
ufMap2 is nil/empty and it checks a random key; update the test to assert both
GetUFMap("ptbr") results are non-nil and non-empty, pick a concrete key from
ufMap1 (e.g., first key via explicit iteration), save its original value, modify
that specific key in ufMap1, then assert that ufMap2 still contains the original
value for that same key; reference GetUFMap and TestGetUFMapReturnsDefensiveCopy
when making these changes.

Comment on lines 22 to 31
## 📦 Supported Entities
- Person (with gender, age, CPF)
- Gender (standalone generation)
- Address (street, number, city, state, UF, ZIP)
- Phone (area code, number)
- Company (name, CNPJ)
- CPF (Brazilian individual taxpayer registry)
- CNPJ (Brazilian company registry)
- Certificates (Birth, Marriage, Death)
- National ID (RG)
- Voter Registration (Título de Eleitor)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

A lista de entidades suportadas ficou incompleta.

O CNPJ standalone saiu daqui, mas a própria PR ainda refatora/adiciona cobertura para esse gerador. Isso passa a impressão de que a geração direta de CNPJ não faz mais parte da API pública.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 22 - 31, A seção "## 📦 Supported Entities" removeu a
menção ao gerador de CNPJ standalone, gerando ambiguidade; atualize essa seção
para incluir explicitamente "CNPJ (standalone)" ou ajustar a linha "Company
(name, CNPJ)" para deixar claro que existe também um gerador direto de CNPJ na
API pública; revise o bloco de entidades (o título "Supported Entities" e as
linhas "Company" e "CNPJ") e reintroduza ou clarifique a entrada para CNPJ para
refletir a implementação atual.

@wellfernandes wellfernandes merged commit eee8dc8 into develop Mar 26, 2026
2 checks passed
@wellfernandes wellfernandes deleted the feature/55-flexibility-improvements branch March 26, 2026 04:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants