diff --git a/README.md b/README.md
index 7480b4d..7d25867 100644
--- a/README.md
+++ b/README.md
@@ -10,30 +10,32 @@
-Brado (BRAzilian DOcs validator) é um pacote Rust para validação de documentos brasileiros.
-Este projeto é inspirado no [validate-docbr](https://github.com/alvarofpp/validate-docbr).
+Brado é um pacote Rust para validação de documentos brasileiros. Este projeto é inspirado na biblioteca Python [validate-docbr](https://github.com/alvarofpp/validate-docbr).
-Para adicionar o pacote ao projeto:
+Brado fornece funções para identificação, validação e geração de documentos brasileiros. O nome desta biblioteca (Brado) é um acronimo de BRAzilian DOcs validator (validador de DOcumentos BRAsileiros).
-```bash
-cargo add brado
-```
+> :warning: A documentação desta biblioteca pode ser acessada [aqui](https://docs.rs/brado/).
-A documentação pode ser acessada [aqui](https://docs.rs/brado/) (ainda em desenvolvimento).
+## Guia Rápido
-## Testes
-
-Para rodar os testes, basta executar o comando a seguir:
+Para adicionar o pacote ao projeto, basta rodar o seguinte comando:
+```bash
+cargo add brado
```
-make test
+
+Ou adicionar a linha a seguir no arquivo `Cargo.toml`:
+
+```toml
+brado = "0.3.5"
```
+
## Documentos
-- [x] CPF: Cadastro de Pessoas Físicas;
+- [x] CPF: Cadastro de Pessoa Física;
- [x] CNH: Carteira Nacional de Habilitação;
- [x] CNPJ: Cadastro Nacional da Pessoa Jurídica;
- [ ] CNS: Cartão Nacional de Saúde;
@@ -49,30 +51,80 @@ Todos os documentos possuem as mesmas funções e funcionam da mesma forma.
### validate
+Valida o documento passado como parâmetro (`&str`). Retorna um valor booleano (`bool`), `true` caso o documento seja válido, ou `false` caso contrário.
+
```rust
use brado::cpf;
+cpf::validate("63929247011"); // true
cpf::validate("639.292.470-11"); // true
-cpf::validate("639.292.470-10"); // false
-cpf::validate("63929247011"); // true
cpf::validate("63929247010"); // false
+cpf::validate("639.292.470-10"); // false
```
### mask
+Mascara o documento passado como parâmetro (`&str`). Retorna a string (`String`) correspondente ao documento mascarado. A string passada não deve possuir símbolos.
+
```rust
use brado::cpf;
cpf::mask("63929247011"); // "639.292.470-11"
+
+cpf::mask("639.292.470-11"); // panic!
+```
+
+### is_bare
+
+Verifica se o documento passado como parâmetro (`&str`) não possui símbolos. Retorna um valor booleano (`bool`), `true` caso o documento não possua símbolos, ou `false` caso contrário.
+
+```rust
+use brado::cpf;
+
+cpf::is_bare("63929247011"); // true
+cpf::is_bare("63929247010"); // true
+
+cpf::is_bare("639.292.470-11"); // false
+cpf::is_bare("639.29247011"); // false
+cpf::is_bare("639292470110"); // false
```
+> OBS: se for utilizada a função `cpf::is_bare` para verificar se um CNPJ não possui símbolos, o resultado será `false`! Isso acontece pois esta função considera que a string é um CPF, ou seja, possui 11 dígitos.
+
+### is_masked
+
+Verifica se o documento passado como parâmetro (`&str`) está mascarado de acordo com o documento correspondente. Retorna um valor booleano (`bool`), `true` caso o documento esteja mascarado, ou `false` caso contrário.
+
+```rust
+use brado::cpf;
+
+cpf::is_masked("639.292.470-10"); // true
+
+cpf::is_masked("63929247011"); // false
+cpf::is_masked("6392.92.470-11"); // false
+cpf::is_masked("639.292.470-110"); // false
+```
+
+> OBS: `cpf::is_masked` verifica se a string passada está mascarada como um CPF. `cnpj::is_masked` verifica se a string passada está mascarada como um CNPJ.
+
### generate
+Gera um novo documento sem símbolos (`String`).
+
+```rust
+use brado::cpf;
+
+cpf::generate(); // "639.292.470-11"
+```
+
+### generate_masked
+
+Gera um novo documento mascarado (`String`).
+
```rust
use brado::cpf;
-cpf::generate(); // "63929247011"
cpf::generate_masked(); // "639.292.470-11"
```
@@ -87,3 +139,12 @@ nix flake clone github:your-github-user/brado --dest ./brado \
&& cd brado 1>/dev/null 2>/dev/null \
&& direnv allow
```
+
+
+## Testes
+
+Para rodar os testes, basta executar o comando a seguir:
+
+```bash
+make test
+```
diff --git a/brado/src/cnh.rs b/brado/src/cnh.rs
index 6bfc1ea..e96ed13 100644
--- a/brado/src/cnh.rs
+++ b/brado/src/cnh.rs
@@ -1,15 +1,44 @@
+//! Utilitários para validação de CNH.
+
use crate::common::{
get_digits, get_symbols, is_repeated, random_digit_vector,
};
-pub fn validate(cnh: &str) -> bool {
- let size: usize = cnh.chars().count();
-
- if size != 11 && !is_masked(cnh) {
+/// Realiza validação de CNH, máscarado ou não.
+/// Retorna `true` se o argumento `doc` for uma CNH válido,
+/// caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNHs válidos:
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::validate("84718735264"); // true
+/// assert!(result);
+///
+/// let result = cnh::validate("847 187 352 64"); // true
+/// assert!(result);
+/// ```
+///
+/// CNHs inválidos:
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::validate("84718735265"); // false
+/// assert!(!result);
+///
+/// let result = cnh::validate("847 187 352 65"); // false
+/// assert!(!result);
+/// ```
+pub fn validate(doc: &str) -> bool {
+ let size: usize = doc.chars().count();
+
+ if size != 11 && !is_masked(doc) {
return false;
}
- let digits: Vec = get_digits(cnh);
+ let digits: Vec = get_digits(doc);
if digits.len() != 11 {
return false;
@@ -24,9 +53,9 @@ pub fn validate(cnh: &str) -> bool {
(d10, d11) == (digits[9], digits[10])
}
-fn generate_digits(cnh_slice: &[u16]) -> (u16, u16) {
- let (d10, dsc): (u16, u16) = generate_first_digit(cnh_slice);
- let d11: u16 = generate_second_digit(cnh_slice, dsc);
+fn generate_digits(doc_slice: &[u16]) -> (u16, u16) {
+ let (d10, dsc): (u16, u16) = generate_first_digit(doc_slice);
+ let d11: u16 = generate_second_digit(doc_slice, dsc);
(d10, d11)
}
@@ -50,13 +79,13 @@ fn generate_first_digit(cnh: &[u16]) -> (u16, u16) {
}
fn generate_second_digit(
- cnh: &[u16],
+ doc: &[u16],
dsc: u16,
) -> u16 {
let mut sum: u16 = 0;
for i in 1..=9 {
- sum += cnh[i - 1] * (i as u16);
+ sum += doc[i - 1] * (i as u16);
}
let mut second: i16 = ((sum % 11) as i16) - (dsc as i16);
@@ -70,34 +99,110 @@ fn generate_second_digit(
second as u16
}
-pub fn is_bare(cnh: &str) -> bool {
- cnh.chars().count() == 11 && get_digits(cnh).len() == 11
+/// Verifica se o argumento `doc` pode ser um CNH sem símbolos.
+/// Se for, retorna `true`, caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNHs válidos:
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::is_bare("84718735264"); // true
+/// assert!(result);
+///
+/// let result = cnh::is_bare("847 187 352 64"); // false
+/// assert!(!result);
+/// ```
+///
+/// CNHs inválidos:
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::is_bare("84718735265"); // true
+/// assert!(result);
+/// ```
+pub fn is_bare(doc: &str) -> bool {
+ doc.chars().count() == 11 && get_digits(doc).len() == 11
}
-pub fn is_masked(cnh: &str) -> bool {
- let symbols: Vec<(usize, char)> = get_symbols(cnh);
-
- if symbols.len() != 3 {
+/// Verifica se o argumento `doc` pode ser um CNH com símbolos.
+/// Se for, retorna `true`, caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNHs válidos:
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::is_masked("847 187 352 64"); // true
+/// assert!(result);
+///
+/// let result = cnh::is_masked("84718735264"); // false
+/// assert!(!result);
+/// ```
+///
+/// CNHs inválidos:
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::is_masked("847 187 352 65"); // true
+/// assert!(result);
+/// ```
+pub fn is_masked(doc: &str) -> bool {
+ let symbols: Vec<(usize, char)> = get_symbols(doc);
+ let digits: Vec = get_digits(doc);
+
+ if symbols.len() != 3 || digits.len() != 11 {
return false;
}
symbols[0] == (3, ' ') && symbols[1] == (7, ' ') && symbols[2] == (11, ' ')
}
-pub fn mask(cnh: &str) -> String {
- if !is_bare(cnh) {
+/// Aplica máscara de CNH no argumento `doc` e retorna resultado.
+/// O argumento deve ser uma string sem símbolos, caso contrário,
+/// deve lançar erro.
+///
+/// ## Exemplos
+///
+/// Documento de 11 dígitos sem máscara:
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::mask("84718735264"); // "847 187 352 64"
+/// assert!(cnh::is_masked(&result)); // true
+/// ```
+///
+/// Documento de 11 dígitos com máscara:
+/// ```should_panic
+/// use brado::cnh;
+///
+/// cnh::mask("847 187 352 64"); // panic!
+/// ```
+pub fn mask(doc: &str) -> String {
+ if !is_bare(doc) {
panic!("The given string cannot be masked as CNH!")
}
format!(
"{} {} {} {}",
- &cnh[0..3],
- &cnh[3..6],
- &cnh[6..9],
- &cnh[9..11],
+ &doc[0..3],
+ &doc[3..6],
+ &doc[6..9],
+ &doc[9..11],
)
}
+/// Gera e retorna um CNH aleatório sem máscara.
+///
+/// ## Exemplo
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::generate(); // "84718735264"
+/// assert!(cnh::is_bare(&result)); // true
+/// ```
pub fn generate() -> String {
let mut cnh: Vec = random_digit_vector(9);
let (d10, dsc): (u16, u16) = generate_first_digit(&cnh);
@@ -111,6 +216,15 @@ pub fn generate() -> String {
.join("")
}
+/// Gera e retorna um CNH aleatório com máscara.
+///
+/// ## Exemplo
+/// ```
+/// use brado::cnh;
+///
+/// let result = cnh::generate_masked(); // "847 187 352 64"
+/// assert!(cnh::is_masked(&result)); // true
+/// ```
pub fn generate_masked() -> String {
mask(&generate())
}
diff --git a/brado/src/cnpj.rs b/brado/src/cnpj.rs
index 96a416a..297aaa4 100644
--- a/brado/src/cnpj.rs
+++ b/brado/src/cnpj.rs
@@ -1,13 +1,42 @@
-use crate::common::{get_digits, get_symbols, random_digit_vector};
+//! Utilitários para validação de CNPJ.
-pub fn validate(cnpj: &str) -> bool {
- let size: usize = cnpj.chars().count();
+use crate::common::{get_digits, get_symbols, random_digit_vector};
- if size != 14 && !is_masked(cnpj) {
+/// Realiza validação de CNPJ, máscarado ou não.
+/// Retorna `true` se o argumento `doc` for um CNPJ válido,
+/// caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNPJs válidos:
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::validate("05200851000100"); // true
+/// assert!(result);
+///
+/// let result = cnpj::validate("05.200.851/0001-00"); // true
+/// assert!(result);
+/// ```
+///
+/// CNPJs inválidos:
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::validate("05200851000101"); // false
+/// assert!(!result);
+///
+/// let result = cnpj::validate("05.200.851/0001-01"); // false
+/// assert!(!result);
+/// ```
+pub fn validate(doc: &str) -> bool {
+ let size: usize = doc.chars().count();
+
+ if size != 14 && !is_masked(doc) {
return false;
}
- let digits: Vec = get_digits(cnpj);
+ let digits: Vec = get_digits(doc);
if digits.len() != 14 {
return false;
@@ -24,29 +53,29 @@ pub fn validate(cnpj: &str) -> bool {
(d13, d14) == (digits[12], digits[13])
}
-fn generate_digits(cnpj_slice: &[u16]) -> (u16, u16) {
- let mut cnpj_slice: Vec = cnpj_slice.to_vec();
+fn generate_digits(doc_slice: &[u16]) -> (u16, u16) {
+ let mut doc_slice: Vec = doc_slice.to_vec();
let weights: Vec = vec![5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
- let d13: u16 = generate_digit(&cnpj_slice, 12, weights);
+ let d13: u16 = generate_digit(&doc_slice, 12, weights);
- cnpj_slice.push(d13);
+ doc_slice.push(d13);
let weights: Vec = vec![6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
- let d14: u16 = generate_digit(&cnpj_slice, 13, weights);
+ let d14: u16 = generate_digit(&doc_slice, 13, weights);
(d13, d14)
}
fn generate_digit(
- cnpj_slice: &[u16],
+ doc_slice: &[u16],
max: usize,
weights: Vec,
) -> u16 {
let mut sum: u16 = 0;
for i in 0..max {
- sum += cnpj_slice[i] * weights[i];
+ sum += doc_slice[i] * weights[i];
}
sum %= 11;
@@ -60,14 +89,61 @@ fn generate_digit(
sum
}
-pub fn is_bare(cnpj: &str) -> bool {
- cnpj.chars().count() == 14 && get_digits(cnpj).len() == 14
+/// Verifica se o argumento `doc` pode ser um CNPJ sem símbolos.
+/// Se for, retorna `true`, caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNPJs válidos:
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::is_bare("05200851000100"); // true
+/// assert!(result);
+///
+/// let result = cnpj::is_bare("05.200.851/0001-00"); // false
+/// assert!(!result);
+/// ```
+///
+/// CNPJs inválidos:
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::is_bare("05200851000101"); // true
+/// assert!(result);
+/// ```
+pub fn is_bare(doc: &str) -> bool {
+ doc.chars().count() == 14 && get_digits(doc).len() == 14
}
-pub fn is_masked(cnpj: &str) -> bool {
- let symbols: Vec<(usize, char)> = get_symbols(cnpj);
-
- if symbols.len() != 4 {
+/// Verifica se o argumento `doc` pode ser um CNPJ com símbolos.
+/// Se for, retorna `true`, caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNPJs válidos:
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::is_masked("05.200.851/0001-00"); // true
+/// assert!(result);
+///
+/// let result = cnpj::is_masked("05200851000100"); // false
+/// assert!(!result);
+/// ```
+///
+/// CNPJs inválidos:
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::is_masked("05.200.851/0001-01"); // true
+/// assert!(result);
+/// ```
+pub fn is_masked(doc: &str) -> bool {
+ let symbols: Vec<(usize, char)> = get_symbols(doc);
+ let digits: Vec = get_digits(doc);
+
+ if symbols.len() != 4 || digits.len() != 14 {
return false;
}
@@ -77,21 +153,50 @@ pub fn is_masked(cnpj: &str) -> bool {
&& symbols[3] == (15, '-')
}
-pub fn mask(cnpj: &str) -> String {
- if !is_bare(cnpj) {
+/// Aplica máscara de CNPJ no argumento `doc` e retorna resultado.
+/// O argumento deve ser uma string sem símbolos, caso contrário,
+/// deve lançar erro.
+///
+/// ## Exemplos
+///
+/// Documento de 14 dígitos sem máscara:
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::mask("05200851000100"); // "05.200.851/0001-00"
+/// assert!(cnpj::is_masked(&result)); // true
+/// ```
+///
+/// Documento de 14 dígitos com máscara:
+/// ```should_panic
+/// use brado::cnpj;
+///
+/// cnpj::mask("05.200.851/0001-00"); // panic!
+/// ```
+pub fn mask(doc: &str) -> String {
+ if !is_bare(doc) {
panic!("The given string cannot be masked as CNPJ!")
}
format!(
"{}.{}.{}/{}-{}",
- &cnpj[0..2],
- &cnpj[2..5],
- &cnpj[5..8],
- &cnpj[8..12],
- &cnpj[12..14],
+ &doc[0..2],
+ &doc[2..5],
+ &doc[5..8],
+ &doc[8..12],
+ &doc[12..14],
)
}
+/// Gera e retorna um CNPJ aleatório sem máscara.
+///
+/// ## Exemplo
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::generate(); // "05200851000100"
+/// assert!(cnpj::is_bare(&result)); // true
+/// ```
pub fn generate() -> String {
let cnpj: Vec = random_digit_vector(12);
let (d13, d14): (u16, u16) = generate_digits(&cnpj);
@@ -103,6 +208,15 @@ pub fn generate() -> String {
.join("")
}
+/// Gera e retorna um CNPJ aleatório com máscara.
+///
+/// ## Exemplo
+/// ```
+/// use brado::cnpj;
+///
+/// let result = cnpj::generate_masked(); // "05.200.851/0001-00"
+/// assert!(cnpj::is_masked(&result)); // true
+/// ```
pub fn generate_masked() -> String {
mask(&generate())
}
diff --git a/brado/src/common.rs b/brado/src/common.rs
index e58a974..40d7500 100644
--- a/brado/src/common.rs
+++ b/brado/src/common.rs
@@ -1,23 +1,63 @@
+//! Funções comuns utilizadas na validação de docos.
+
use rand::Rng;
use std::collections::HashSet;
const RADIX: u32 = 10;
+/// Verifica se o vetor de dígitos possui um único numeral.
+/// Se possuir, retorna `true`, caso contrário, retorna `false`.
+///
+/// ## Exemplo
+///
+/// ```
+/// use brado::common::is_repeated;
+///
+/// let result = is_repeated(&vec![1, 1, 1]); // true
+/// assert!(result);
+///
+/// let result = is_repeated(&vec![1, 2, 1]); // false
+/// assert!(!result);
+/// ```
pub fn is_repeated(digits: &[u16]) -> bool {
let a_set: HashSet = HashSet::from_iter(digits.iter().cloned());
a_set.len() == 1
}
-pub fn get_digits(document: &str) -> Vec {
- document
- .chars()
+/// Extrai e retorna o vetor dígitos de uma string (`&str`).
+///
+/// ## Exemplo
+///
+/// ```
+/// use brado::common::get_digits;
+///
+/// let result = get_digits("111");
+/// assert_eq!(result, vec![1, 1, 1]);
+///
+/// let result = get_digits("121");
+/// assert_eq!(result, vec![1, 2, 1]);
+/// ```
+pub fn get_digits(doc: &str) -> Vec {
+ doc.chars()
.filter_map(|c| c.to_digit(RADIX).map(|c| c as u16))
.collect()
}
-pub fn get_symbols(document: &str) -> Vec<(usize, char)> {
- document
- .chars()
+/// Extrai e retorna o vetor de símbolos de uma string (`&str`).
+/// O vetor resultante é um vetor de tuplas de dois elementos: o
+/// primeiro representa a posição do símbolo na string e o segundo
+/// o próprio símbolo.
+///
+/// ## Exemplo
+///
+/// ```
+/// use brado::common::get_symbols;
+///
+/// let result = get_symbols("1.1-1");
+/// assert_eq!(result, vec![(1, '.'), (3, '-')]);
+/// ```
+pub fn get_symbols(doc: &str) -> Vec<(usize, char)> {
+ doc.chars()
.enumerate()
.filter_map(|(i, c)| match c.to_digit(RADIX) {
Some(_) => None,
@@ -26,14 +66,34 @@ pub fn get_symbols(document: &str) -> Vec<(usize, char)> {
.collect()
}
-pub fn unmask(document: &str) -> String {
- document
- .chars()
+/// Remove os símbolos (desmascara) de uma string (`&str`)
+/// e retorna a string resultante.
+///
+/// ## Exemplo
+///
+/// ```
+/// use brado::common::unmask;
+///
+/// let result = unmask("1.1-1");
+/// assert_eq!(result, String::from("111"));
+/// ```
+pub fn unmask(doc: &str) -> String {
+ doc.chars()
.filter_map(|c| c.to_digit(RADIX).map(|c| c.to_string()))
.collect::>()
.join("")
}
+/// Gera e retorna um vetor de dígitos aleatórios com o tamanho `size`.
+///
+/// ## Exemplo
+///
+/// ```
+/// use brado::common::random_digit_vector;
+///
+/// let result = random_digit_vector(10);
+/// assert_eq!(result.len(), 10);
+/// ```
pub fn random_digit_vector(size: usize) -> Vec {
let mut rng = rand::thread_rng();
let mut digits: Vec = vec![];
diff --git a/brado/src/cpf.rs b/brado/src/cpf.rs
index 787648d..0f60f94 100644
--- a/brado/src/cpf.rs
+++ b/brado/src/cpf.rs
@@ -1,15 +1,44 @@
+//! Utilitários para validação de CPF.
+
use crate::common::{
get_digits, get_symbols, is_repeated, random_digit_vector,
};
-pub fn validate(cpf: &str) -> bool {
- let size: usize = cpf.chars().count();
-
- if size != 11 && !is_masked(cpf) {
+/// Realiza validação de CPF, máscarado ou não.
+/// Retorna `true` se o argumento `doc` for um CPF válido,
+/// caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CPFs válidos:
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::validate("63929247011"); // true
+/// assert!(result);
+///
+/// let result = cpf::validate("639.292.470-11"); // true
+/// assert!(result);
+/// ```
+///
+/// CPFs inválidos:
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::validate("63929247010"); // false
+/// assert!(!result);
+///
+/// let result = cpf::validate("639.292.470-10"); // false
+/// assert!(!result);
+/// ```
+pub fn validate(doc: &str) -> bool {
+ let size: usize = doc.chars().count();
+
+ if size != 11 && !is_masked(doc) {
return false;
}
- let digits: Vec = get_digits(cpf);
+ let digits: Vec = get_digits(doc);
if digits.len() != 11 || is_repeated(&digits) {
return false;
@@ -20,22 +49,22 @@ pub fn validate(cpf: &str) -> bool {
(d10, d11) == (digits[9], digits[10])
}
-fn generate_digits(cpf_slice: &[u16]) -> (u16, u16) {
- let d10: u16 = generate_digit(cpf_slice, 10);
- let d11: u16 = generate_digit(cpf_slice, 11);
+fn generate_digits(doc_slice: &[u16]) -> (u16, u16) {
+ let d10: u16 = generate_digit(doc_slice, 10);
+ let d11: u16 = generate_digit(doc_slice, 11);
(d10, d11)
}
fn generate_digit(
- cpf_slice: &[u16],
+ doc_slice: &[u16],
max: u16,
) -> u16 {
let mut sum: u16 = 0;
for i in (2..=max).rev() {
let idx: usize = (max - i) as usize;
- sum += cpf_slice[idx] * i;
+ sum += doc_slice[idx] * i;
}
sum = (sum * 10) % 11;
@@ -47,34 +76,110 @@ fn generate_digit(
sum
}
-pub fn is_bare(cpf: &str) -> bool {
- cpf.chars().count() == 11 && get_digits(cpf).len() == 11
+/// Verifica se o argumento `doc` pode ser um CPF sem símbolos.
+/// Se for, retorna `true`, caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CPFs válidos:
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::is_bare("63929247011"); // true
+/// assert!(result);
+///
+/// let result = cpf::is_bare("639.292.470-11"); // false
+/// assert!(!result);
+/// ```
+///
+/// CPFs inválidos:
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::is_bare("63929247010"); // true
+/// assert!(result);
+/// ```
+pub fn is_bare(doc: &str) -> bool {
+ doc.chars().count() == 11 && get_digits(doc).len() == 11
}
-pub fn is_masked(cpf: &str) -> bool {
- let symbols: Vec<(usize, char)> = get_symbols(cpf);
-
- if symbols.len() != 3 {
+/// Verifica se o argumento `doc` pode ser um CPF com símbolos.
+/// Se for, retorna `true`, caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CPFs válidos:
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::is_masked("639.292.470-11"); // true
+/// assert!(result);
+///
+/// let result = cpf::is_masked("63929247011"); // false
+/// assert!(!result);
+/// ```
+///
+/// CPFs inválidos:
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::is_masked("639.292.470-10"); // true
+/// assert!(result);
+/// ```
+pub fn is_masked(doc: &str) -> bool {
+ let symbols: Vec<(usize, char)> = get_symbols(doc);
+ let digits: Vec = get_digits(doc);
+
+ if symbols.len() != 3 || digits.len() != 11 {
return false;
}
symbols[0] == (3, '.') && symbols[1] == (7, '.') && symbols[2] == (11, '-')
}
-pub fn mask(cpf: &str) -> String {
- if !is_bare(cpf) {
+/// Aplica máscara de CPF no argumento `doc` e retorna resultado.
+/// O argumento deve ser uma string sem símbolos, caso contrário,
+/// deve lançar erro.
+///
+/// ## Exemplos
+///
+/// Documento de 11 dígitos sem máscara:
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::mask("63929247011"); // "639.292.470-11"
+/// assert!(cpf::is_masked(&result)); // true
+/// ```
+///
+/// Documento de 11 dígitos com máscara:
+/// ```should_panic
+/// use brado::cpf;
+///
+/// cpf::mask("639.292.470-11"); // panic!
+/// ```
+pub fn mask(doc: &str) -> String {
+ if !is_bare(doc) {
panic!("The given string cannot be masked as CPF!")
}
format!(
"{}.{}.{}-{}",
- &cpf[0..3],
- &cpf[3..6],
- &cpf[6..9],
- &cpf[9..11],
+ &doc[0..3],
+ &doc[3..6],
+ &doc[6..9],
+ &doc[9..11],
)
}
+/// Gera e retorna um CPF aleatório sem máscara.
+///
+/// ## Exemplo
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::generate(); // "63929247011"
+/// assert!(cpf::is_bare(&result)); // true
+/// ```
pub fn generate() -> String {
let mut cpf: Vec = random_digit_vector(9);
cpf.push(generate_digit(&cpf, 10));
@@ -86,6 +191,15 @@ pub fn generate() -> String {
.join("")
}
+/// Gera e retorna um CPF aleatório com máscara.
+///
+/// ## Exemplo
+/// ```
+/// use brado::cpf;
+///
+/// let result = cpf::generate_masked(); // "639.292.470-11"
+/// assert!(cpf::is_masked(&result)); // true
+/// ```
pub fn generate_masked() -> String {
mask(&generate())
}
diff --git a/brado/src/docs.rs b/brado/src/docs.rs
index a1542ef..75055b7 100644
--- a/brado/src/docs.rs
+++ b/brado/src/docs.rs
@@ -1,15 +1,98 @@
+//! Utilitários para validação de documentos.
+
use crate::cnh;
use crate::cnpj;
use crate::cpf;
-pub fn is_cpf(document: &str) -> bool {
- cpf::validate(document)
+/// Verifica se um documento `doc` é um CPF, máscarado ou não.
+/// Retorna `true` se o argumento `doc` for um CPF válido,
+/// caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CPFs válidos:
+/// ```
+/// use brado::docs;
+///
+/// let result = docs::is_cpf("63929247011"); // true
+/// assert!(result);
+///
+/// let result = docs::is_cpf("639.292.470-11"); // true
+/// assert!(result);
+/// ```
+///
+/// CPFs inválidos:
+/// ```
+/// use brado::docs;
+///
+/// let result = docs::is_cpf("63929247010"); // false
+/// assert!(!result);
+///
+/// let result = docs::is_cpf("639.292.470-10"); // false
+/// assert!(!result);
+/// ```
+pub fn is_cpf(doc: &str) -> bool {
+ cpf::validate(doc)
}
-pub fn is_cnpj(document: &str) -> bool {
- cnpj::validate(document)
+/// Verifica se um documento `doc` é um CNPJ, máscarado ou não.
+/// Retorna `true` se o argumento `doc` for um CNPJ válido,
+/// caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNPJs válidos:
+/// ```
+/// use brado::docs;
+///
+/// let result = docs::is_cnpj("05200851000100"); // true
+/// assert!(result);
+///
+/// let result = docs::is_cnpj("05.200.851/0001-00"); // true
+/// assert!(result);
+/// ```
+///
+/// CNPJs inválidos:
+/// ```
+/// use brado::docs;
+///
+/// let result = docs::is_cnpj("05200851000101"); // false
+/// assert!(!result);
+///
+/// let result = docs::is_cnpj("05.200.851/0001-01"); // false
+/// assert!(!result);
+/// ```
+pub fn is_cnpj(doc: &str) -> bool {
+ cnpj::validate(doc)
}
-pub fn is_cnh(document: &str) -> bool {
- cnh::validate(document)
+/// Verifica se um documento `doc` é uma CNH, máscarado ou não.
+/// Retorna `true` se o argumento `doc` for uma CNH válido,
+/// caso contrário, retorna `false`.
+///
+/// ## Exemplos
+///
+/// CNHs válidos:
+/// ```
+/// use brado::docs;
+///
+/// let result = docs::is_cnh("84718735264"); // true
+/// assert!(result);
+///
+/// let result = docs::is_cnh("847 187 352 64"); // true
+/// assert!(result);
+/// ```
+///
+/// CNHs inválidos:
+/// ```
+/// use brado::docs;
+///
+/// let result = docs::is_cnh("84718735265"); // false
+/// assert!(!result);
+///
+/// let result = docs::is_cnh("847 187 352 65"); // false
+/// assert!(!result);
+/// ```
+pub fn is_cnh(doc: &str) -> bool {
+ cnh::validate(doc)
}
diff --git a/brado/src/lib.rs b/brado/src/lib.rs
index aa19a2a..c3d62a7 100644
--- a/brado/src/lib.rs
+++ b/brado/src/lib.rs
@@ -1,11 +1,25 @@
-//! # brado documentation
+// Copyright 2024 Developers of the Brado project.
+//
+// Licensed under the MIT license .
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! Utilitários para validação de documentos brasileiros
//!
-//! brado is a brazilian docs validator.
+//! Brado fornece funções para identificação, validação e geração de documentos
+//! brasileiros. O nome desta biblioteca (Brado) é um acronimo de BRAzilian
+//! DOcs validator (validador de DOcumentos BRAsileiros).
+//!
+//! # Guia Rápido
+//!
+//! Para utilizar a biblioteca, basta importá-la no arquivo (`use brado`),
+//! escolher o módulo correspondente ao documento e chamar a função desejada.
+//! Por exemplo, para validar um CPF, basta utilizar o código a seguir:
//!
-//! ## Example
//! ```
-//! use brado::cpf;
-//! cpf::validate("639.292.470-11");
+//! use brado;
+//! let result = brado::cpf::validate("639.292.470-11");
+//! assert!(result);
//! ```
pub mod cnh;
pub mod cnpj;
diff --git a/brado/tests/cnpj.rs b/brado/tests/cnpj.rs
index c08cf3e..f7c7936 100644
--- a/brado/tests/cnpj.rs
+++ b/brado/tests/cnpj.rs
@@ -50,6 +50,12 @@ mod cnpj_tests {
assert_eq!(brado::cnpj::is_bare(masked_cnpj), false);
}
+ #[test]
+ fn cnpj_is_bare_3_other_document() {
+ let bare_document: &str = "052008510001001";
+ assert_eq!(brado::cnpj::is_bare(bare_document), false);
+ }
+
#[test]
fn cnpj_is_masked_1_masked_cnpj() {
let masked_cnpj: &str = "05.200.851/0001-00";
@@ -62,6 +68,18 @@ mod cnpj_tests {
assert_eq!(brado::cnpj::is_masked(bare_cnpj), false);
}
+ #[test]
+ fn cnpj_is_masked_3_other_document() {
+ let masked_document: &str = "0.520.085/1000-100";
+ assert_eq!(brado::cnpj::is_masked(masked_document), false);
+ }
+
+ #[test]
+ fn cnpj_is_masked_4_other_document() {
+ let masked_document: &str = "00.520.085/1000-100";
+ assert_eq!(brado::cnpj::is_masked(masked_document), false);
+ }
+
#[test]
fn cnpj_mask_1_bare_cnpj() {
let bare_cnpj: &str = "05200851000100";
@@ -93,7 +111,7 @@ mod cnpj_tests {
}
#[test]
- fn cpf_generate_masked_1() {
+ fn cnpj_generate_masked_1() {
let cnpj = brado::cnpj::generate_masked();
assert_eq!(brado::cnpj::validate(&cnpj), true);
assert_eq!(brado::cnpj::is_masked(&cnpj), true);
diff --git a/brado/tests/cpf.rs b/brado/tests/cpf.rs
index a3216b2..8e28bea 100644
--- a/brado/tests/cpf.rs
+++ b/brado/tests/cpf.rs
@@ -58,6 +58,12 @@ mod cpf_tests {
assert_eq!(brado::cpf::is_bare(masked_cpf), false);
}
+ #[test]
+ fn cpf_is_bare_3_other_document() {
+ let bare_document: &str = "639292470110";
+ assert_eq!(brado::cpf::is_bare(bare_document), false);
+ }
+
#[test]
fn cpf_is_masked_1_masked_cpf() {
let masked_cpf: &str = "639.292.470-11";
@@ -70,6 +76,18 @@ mod cpf_tests {
assert_eq!(brado::cpf::is_masked(bare_cpf), false);
}
+ #[test]
+ fn cpf_is_masked_3_other_document() {
+ let masked_document: &str = "6392.292.470-11";
+ assert_eq!(brado::cpf::is_masked(masked_document), false);
+ }
+
+ #[test]
+ fn cpf_is_masked_4_other_document() {
+ let masked_document: &str = "639.292.470-110";
+ assert_eq!(brado::cpf::is_masked(masked_document), false);
+ }
+
#[test]
fn cpf_mask_1_bare_cpf() {
let bare_cpf: &str = "63929247011";