Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Faker::DrivingLicence #1433

Merged
merged 3 commits into from
Oct 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions doc/unreleased/driving_licence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Faker::DrivingLicence

```ruby
# Generate a licence number in GB format, as issued in England, Scotland and Wales
# The DVSA does not publish their checksum algorithm, so the last 3 characters
# are random
# Optional arguments: last_name, initials, date_of_birth, gender
Faker::DrivingLicence.british_driving_licence #=> "MCDER712081VF7EK"
Faker::DrivingLicence.british_driving_licence(last_name: "O'Carroll",
initials: "J",
gender: :female,
date_of_birth: Date.parse("1986-10-24")) #=> "OCARR815246J91HT"

# Generate a Northern Irish licence number
Faker::DrivingLicence.northern_irish_driving_licence #=> "70702548"

# Generate a UK driving licence number in either GB or NI format, at a rate
# consistent with their relative populations
# Optional arguments: last_name, initials, date_of_birth, gender
Faker::DrivingLicence.uk_driving_licence #=> "OCARR815246J91HT"
Faker::DrivingLicence.uk_driving_licence #=> "70702548"
59 changes: 59 additions & 0 deletions lib/faker/driving_licence.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

module Faker
class DrivingLicence < Base
GB_PADDING = '9999'
NI_CHANCE = 0.03 # NI Pop is about 3% of total UK population

class << self
def british_driving_licence(last_name: Faker::Name.last_name,
initials: Faker::Name.initials,
gender: random_gender,
date_of_birth: Faker::Date.birthday(18, 65))
[
gb_licence_padding(last_name, 5),
gb_licence_year(date_of_birth, gender),
gb_licence_padding(initials, 2),
gb_licence_checksum
].join
end

def northern_irish_driving_licence
Faker::Number.number(8)
end

def uk_driving_licence(*args)
if Faker::Config.random.rand < NI_CHANCE
northern_irish_driving_licence
else
british_driving_licence(*args)
end
end

private

def random_gender
%i[male female].sample(random: Faker::Config.random)
end

def gb_licence_padding(str, num_chars)
prepped = str.upcase.gsub(%r{[^A-Z]}, '') + GB_PADDING
prepped[0..(num_chars - 1)]
end

def gb_licence_year(dob, gender)
decade = (dob.year / 10) % 10
year = dob.year % 10
month = gender == :female ? dob.month + 5 : dob.month
# Rubocop's preferred formatting is pretty gory
# rubocop:disable FormatString
"#{decade}#{'%02d' % month}#{'%02d' % dob.day}#{year}"
# rubocop:enable FormatString
end

def gb_licence_checksum
regexify(/[0-9][A-Z][A-Z]/)
end
end
end
end
68 changes: 68 additions & 0 deletions test/test_faker_driving_licence.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true

require_relative 'test_helper'

class TestFakerDrivingLicence < Test::Unit::TestCase
def setup
@tester = Faker::DrivingLicence
end

def test_valid_gb_licence
sample = @tester.british_driving_licence
# GB Licence number is 16 characters long
assert_equal 16, sample.length
# First 5 characters are the last_name, right-padded with '9'
assert_match %r{[A-Z][A-Z9]{4}}, sample[0..4]
# Next 6 are digits
assert_match %r{[0-9]{6}}, sample[5..10]
# comprising:
# Single digit decade of birth
assert_includes 0..9, sample[5].to_i
# 2 digit month of birth (add 5 if female)
assert_includes 1..17, sample[6..7].to_i
# 2 digit day of birth
assert_includes 1..31, sample[8..9].to_i
# and least significant digit of birth year
assert_includes 0..9, sample[10].to_i
# Next 2 are first 2 initials of forenames, padded with '9'
assert_match %r{[A-Z][A-Z9]}, sample[11..12]
# Last stanza is a tie-breaker digit + 2 letter checksum
assert_match %r{[0-9][A-Z0-9]{2}}, sample[13..15]
end

def test_valid_northern_irish_licence
sample = @tester.northern_irish_driving_licence
# NI licence is an opaque 8-digit number
assert_equal 8, sample.length
assert_match %r{[0-9]{8}}, sample
end

def test_uk_licence
sample = @tester.uk_driving_licence
assert_includes [8, 16], sample.length
end

def test_british_licence_correctly_mangles_last_name
padded = @tester.british_driving_licence(last_name: 'Judd')
assert_equal 'JUDD9', padded[0..4]
truncated = @tester.british_driving_licence(last_name: 'Hamilton')
assert_match %r{HAMIL[0-9]}, truncated[0..5]
cleaned = @tester.british_driving_licence(last_name: "O'Carroll")
assert_equal 'OCARR', cleaned[0..4]
end

def test_british_licence_correctly_mangles_date_of_birth
date_of_birth = Date.parse('1978-02-13')
male = @tester.british_driving_licence(date_of_birth: date_of_birth, gender: :male)
assert_equal '702138', male[5..10]
female = @tester.british_driving_licence(date_of_birth: date_of_birth, gender: :female)
assert_equal '707138', female[5..10]
end

def test_british_licence_correctly_builds_initials
padded = @tester.british_driving_licence(initials: 'A')
assert_equal 'A9', padded[11..12]
truncated = @tester.british_driving_licence(initials: 'NLTC')
assert_equal 'NL', truncated[11..12]
end
end
1 change: 1 addition & 0 deletions unreleased_CONTENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Contents
- [Faker::Demographic](doc/unreleased/demographic.md)
- [Faker::Dessert](doc/unreleased/dessert.md)
- [Faker::Device](doc/unreleased/device.md)
- [Faker::DrivingLicence](doc/unreleased/driving_licence.md)
- [Faker::DrWho](doc/unreleased/dr_who.md)
- [Faker::DumbAndDumber](doc/unreleased/dumb_and_dumber.md)
- [Faker::Dune](doc/unreleased/dune.md)
Expand Down