Skip to content

Commit

Permalink
Add Brazilian documents generation and documentation (faker-ruby#1495)
Browse files Browse the repository at this point in the history
* Change default parameter format in brazilian_citizen_number

* Add alias to brazilian_citizen_number

* Add Brazilian ID generator

* Change generator for Brazilian ID number
Add alias for Brazilian ID number

* Add docs for Brazilian Citizen Number (CPF)

* Add docs for Brazilian ID (RG)

* Add tests for brazilian id digit

* Remove if statement from brazilian id digit method

* Refactor brazilian_document_remainder and rename it to brazilian_document_digit

* Add tests for brazilian_citizen_number_digit

* Add tests for brazilian_document_digit

* Add tests for brazilian_document_checksum

* Add tests for brazilian_id_checksum_digit

* Add tests for brazilian_citizen_number_checksum_digit

* Simplify brazilian document tests

* Add Brazilian ID (RG) to ID Number docs

* Minor changes

* Remove unused file

* Minor fixes

* Readd docs after deleting unreleased docs folder

* docs
  • Loading branch information
lucasqueiroz authored and vbrazo committed Aug 11, 2019
1 parent c98916f commit 125cd93
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 16 deletions.
7 changes: 5 additions & 2 deletions doc/default/id_number.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ Faker::IDNumber.valid_south_african_id_number #=> "8105128870184"
Faker::IDNumber.invalid_south_african_id_number #=> "1642972065088"

# Generate a Brazilian citizen number (CPF)
# Keyword arguments: formatted
Faker::IDNumber.brazilian_citizen_number #=> "53540542221"
Faker::IDNumber.brazilian_citizen_number(formatted: true) #=> 000.000.000-00

# Generate a formatted Brazilian CPF
# Generate a Brazilian ID Number (RG)
# Keyword arguments: formatted
Faker::IDNumber.brazilian_citizen_number(formatted: true) #=> 000.000.000-00
Faker::IDNumber.brazilian_id #=> 1212312312
Faker::IDNumber.brazilian_id(formatted: true) #=> 12.123.123-12
```
41 changes: 39 additions & 2 deletions lib/faker/default/id_number.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class IDNumber < Base
].freeze
ZA_RACE_DIGIT = '8'
ZA_CITIZENSHIP_DIGITS = %w[0 1].freeze
BRAZILIAN_ID_FORMAT = /(\d{1,2})(\d{3})(\d{3})([\dX])/
BRAZILIAN_ID_FROM = 10_000_000
BRAZILIAN_ID_TO = 99_999_999

class << self
def valid
Expand Down Expand Up @@ -83,6 +86,17 @@ def brazilian_citizen_number(formatted: false)
formatted ? format('%s.%s.%s-%s', *number.scan(/\d{2,3}/).flatten) : number
end

alias brazilian_cpf brazilian_citizen_number

def brazilian_id(formatted: false)
digits = Faker::Number.between(to: BRAZILIAN_ID_FROM, from: BRAZILIAN_ID_TO).to_s
check_digit = brazilian_id_checksum_digit(digits)
number = [digits, check_digit].join
formatted ? format('%s.%s.%s-%s', *number.scan(BRAZILIAN_ID_FORMAT).flatten) : number
end

alias brazilian_rg brazilian_id

private

def south_african_id_checksum_digit(id_number)
Expand All @@ -104,13 +118,36 @@ def south_african_id_checksum_digit(id_number)
end

def brazilian_citizen_number_checksum_digit(digits)
digit_sum = digits.chars.each_with_index.inject(0) do |acc, (digit, i)|
checksum = brazilian_document_checksum(digits)
brazilian_document_digit(checksum)
end

def brazilian_id_checksum_digit(digits)
checksum = brazilian_document_checksum(digits)
brazilian_document_digit(checksum, id: true)
end

def brazilian_document_checksum(digits)
digits.chars.each_with_index.inject(0) do |acc, (digit, i)|
acc + digit.to_i * (digits.size + 1 - i)
end * 10
remainder = digit_sum % 11
end

def brazilian_document_digit(checksum, id = false)
remainder = checksum % 11
id ? brazilian_id_digit(remainder) : brazilian_citizen_number_digit(remainder)
end

def brazilian_citizen_number_digit(remainder)
remainder == 10 ? '0' : remainder.to_s
end

def brazilian_id_digit(remainder)
subtraction = 11 - remainder.to_i
digits = { 10 => 'X', 11 => '0' }
digits.include?(subtraction) ? digits[subtraction] : subtraction.to_s
end

def _translate(key)
parse("id_number.#{key}")
end
Expand Down
73 changes: 61 additions & 12 deletions test/faker/default/test_faker_id_number.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,74 @@ def test_brazilian_citizen_number
sample = @tester.brazilian_citizen_number
assert_match(/^\d{11}$/, sample)
assert_match(/(\d)((?!\1)\d)+/, sample)
digit_sum = sample[0..8].chars.each_with_index.inject(0) do |acc, (digit, i)|
acc + digit.to_i * (10 - i)
end * 10
remainder = digit_sum % 11
first_digit = remainder == 10 ? '0' : remainder.to_s
assert_equal sample[9], first_digit
digit_sum = sample[0..9].chars.each_with_index.inject(0) do |acc, (digit, i)|
acc + digit.to_i * (11 - i)
end * 10
remainder = digit_sum % 11
second_digit = remainder == 10 ? '0' : remainder.to_s
assert_equal sample[10], second_digit
end

def test_brazilian_citizen_number_formatted
sample = @tester.brazilian_citizen_number(formatted: true)
assert_match(/^\d{3}\.\d{3}\.\d{3}-\d{2}$/, sample)
end

def test_brazilian_id
sample = @tester.brazilian_id
assert_match(/^\d{9}$/, sample)
assert_match(/(\d)((?!\1)\d)+/, sample)
end

def test_brazilian_id_formatted
sample = @tester.brazilian_id(formatted: true)
assert_match(/^\d{1,2}.\d{3}.\d{3}-[\dX]$/, sample)
end

def test_brazilian_citizen_number_checksum_digit
digits = '128991760'
checksum_digit = Faker::IDNumber.send(:brazilian_citizen_number_checksum_digit, digits)
assert_equal checksum_digit, '4'
digits = '1289917604'
checksum_digit = Faker::IDNumber.send(:brazilian_citizen_number_checksum_digit, digits)
assert_equal checksum_digit, '8'
end

def test_brazilian_id_checksum_digit
digits = '41987080'
checksum_digit = Faker::IDNumber.send(:brazilian_id_checksum_digit, digits)
assert_equal checksum_digit, '5'
end

def test_brazilian_document_checksum
digits = '123456789'
checksum = Faker::IDNumber.send(:brazilian_document_checksum, digits)
assert_equal checksum, 2100
end

def test_brazilian_document_digit
citizen_number_digit10 = Faker::IDNumber.send(:brazilian_document_digit, 10)
citizen_number_digit_other = Faker::IDNumber.send(:brazilian_document_digit, 9)
id_digit10 = Faker::IDNumber.send(:brazilian_document_digit, 1, true)
id_digit11 = Faker::IDNumber.send(:brazilian_document_digit, 0, true)
id_digit_other = Faker::IDNumber.send(:brazilian_document_digit, 2, true)
assert_equal citizen_number_digit10, '0'
assert_equal citizen_number_digit_other, '9'
assert_equal id_digit10, 'X'
assert_equal id_digit11, '0'
assert_equal id_digit_other, '9'
end

def test_brazilian_citizen_number_digit
digit10 = Faker::IDNumber.send(:brazilian_citizen_number_digit, 10)
digit_other = Faker::IDNumber.send(:brazilian_citizen_number_digit, 9)
assert_equal digit10, '0'
assert_equal digit_other, '9'
end

def test_brazilian_id_digit
digit10 = Faker::IDNumber.send(:brazilian_id_digit, 1)
digit11 = Faker::IDNumber.send(:brazilian_id_digit, 0)
digit_other = Faker::IDNumber.send(:brazilian_id_digit, 2)
assert_equal digit10, 'X'
assert_equal digit11, '0'
assert_equal digit_other, '9'
end

private

def south_african_id_number_to_date_of_birth_string(sample)
Expand Down

0 comments on commit 125cd93

Please sign in to comment.