-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add module for generating driving licences (#1433)
- Loading branch information
Showing
4 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters