ffaker 2.21.0 → 2.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +131 -17
  3. data/Gemfile +15 -0
  4. data/README.md +18 -6
  5. data/REFERENCE.md +1012 -969
  6. data/Rakefile +16 -47
  7. data/bin/console +9 -0
  8. data/ffaker.gemspec +9 -23
  9. data/lib/ffaker/address.rb +4 -4
  10. data/lib/ffaker/address_fr.rb +3 -5
  11. data/lib/ffaker/address_it.rb +1 -4
  12. data/lib/ffaker/address_ua.rb +1 -1
  13. data/lib/ffaker/avatar.rb +11 -3
  14. data/lib/ffaker/bank.rb +1 -1
  15. data/lib/ffaker/bank_us.rb +33 -0
  16. data/lib/ffaker/book.rb +15 -7
  17. data/lib/ffaker/cheesy_lingo.rb +2 -2
  18. data/lib/ffaker/code.rb +1 -1
  19. data/lib/ffaker/company.rb +2 -2
  20. data/lib/ffaker/company_fr.rb +2 -2
  21. data/lib/ffaker/crypto.rb +14 -0
  22. data/lib/ffaker/data/address_de/state +1 -0
  23. data/lib/ffaker/data/jo_jo/first_names +356 -0
  24. data/lib/ffaker/data/jo_jo/full_names +225 -0
  25. data/lib/ffaker/data/jo_jo/last_names +153 -0
  26. data/lib/ffaker/data/jo_jo/stands +149 -0
  27. data/lib/ffaker/date.rb +40 -0
  28. data/lib/ffaker/filesystem.rb +12 -2
  29. data/lib/ffaker/geolocation.rb +2 -2
  30. data/lib/ffaker/identification_br.rb +3 -12
  31. data/lib/ffaker/identification_ec.rb +39 -0
  32. data/lib/ffaker/identification_es_cl.rb +2 -2
  33. data/lib/ffaker/identification_es_co.rb +1 -1
  34. data/lib/ffaker/identification_kr.rb +11 -4
  35. data/lib/ffaker/identification_pl.rb +6 -6
  36. data/lib/ffaker/identification_tw.rb +1 -1
  37. data/lib/ffaker/image.rb +28 -4
  38. data/lib/ffaker/jo_jo.rb +24 -0
  39. data/lib/ffaker/lorem_ja.rb +1 -1
  40. data/lib/ffaker/lorem_ru.rb +1 -1
  41. data/lib/ffaker/movie.rb +1 -1
  42. data/lib/ffaker/name_fr.rb +4 -3
  43. data/lib/ffaker/name_pl.rb +1 -1
  44. data/lib/ffaker/number.rb +6 -2
  45. data/lib/ffaker/phone_number_de.rb +3 -3
  46. data/lib/ffaker/skill.rb +1 -1
  47. data/lib/ffaker/ssn.rb +4 -2
  48. data/lib/ffaker/ssn_se.rb +2 -2
  49. data/lib/ffaker/string.rb +1 -1
  50. data/lib/ffaker/time.rb +3 -3
  51. data/lib/ffaker/utils/module_utils.rb +5 -6
  52. data/lib/ffaker/utils/unique_utils.rb +33 -21
  53. data/lib/ffaker/vehicle.rb +2 -2
  54. data/lib/{version.rb → ffaker/version.rb} +1 -1
  55. data/lib/ffaker.rb +63 -191
  56. data/scripts/reference.rb +8 -10
  57. data/test/helper.rb +3 -5
  58. data/test/test_address_da.rb +3 -3
  59. data/test/test_address_fi.rb +2 -2
  60. data/test/test_address_se.rb +2 -2
  61. data/test/test_avatar.rb +30 -7
  62. data/test/test_bank_us.rb +35 -0
  63. data/test/test_book.rb +29 -0
  64. data/test/test_cheesy_lingo.rb +1 -1
  65. data/test/test_color.rb +3 -3
  66. data/test/test_crypto.rb +15 -0
  67. data/test/test_date.rb +47 -0
  68. data/test/test_filesystem.rb +30 -4
  69. data/test/test_freedom_ipsum.rb +1 -1
  70. data/test/test_gender_it.rb +1 -1
  71. data/test/test_gender_ja.rb +1 -1
  72. data/test/test_gender_jp.rb +1 -1
  73. data/test/test_gender_pl.rb +1 -1
  74. data/test/test_healthcare_ru.rb +1 -1
  75. data/test/test_hipster_ipsum.rb +1 -1
  76. data/test/test_html_ipsum.rb +2 -2
  77. data/test/test_identification.rb +12 -2
  78. data/test/test_identification_ec.rb +33 -0
  79. data/test/test_identification_es_mx.rb +3 -1
  80. data/test/test_identification_it.rb +12 -1
  81. data/test/test_identification_kr.rb +3 -3
  82. data/test/test_image.rb +51 -5
  83. data/test/test_internet.rb +3 -1
  84. data/test/test_internet_se.rb +5 -2
  85. data/test/test_jo_jo.rb +29 -0
  86. data/test/test_lorem_br.rb +2 -2
  87. data/test/test_lorem_cn.rb +3 -3
  88. data/test/test_lorem_fr.rb +3 -3
  89. data/test/test_lorem_ie.rb +2 -2
  90. data/test/test_lorem_kr.rb +3 -3
  91. data/test/test_lorem_pl.rb +2 -2
  92. data/test/test_lorem_ru.rb +3 -3
  93. data/test/test_lorem_ua.rb +3 -3
  94. data/test/test_module_utils.rb +33 -0
  95. data/test/test_name_da.rb +1 -1
  96. data/test/test_name_ph.rb +1 -1
  97. data/test/test_name_ru.rb +2 -2
  98. data/test/test_name_ua.rb +2 -2
  99. data/test/test_number.rb +13 -1
  100. data/test/test_phone_number_nl.rb +1 -1
  101. data/test/test_phone_number_se.rb +1 -1
  102. data/test/test_phone_number_sg.rb +8 -8
  103. data/test/test_unique_utils.rb +29 -5
  104. data/test/test_units.rb +6 -6
  105. data/test/test_units_english.rb +15 -15
  106. data/test/test_units_metric.rb +15 -15
  107. data/test/test_vehicle.rb +22 -0
  108. metadata +24 -241
@@ -11,4 +11,37 @@ class TestModuleUtils < Test::Unit::TestCase
11
11
  assert result.frozen?
12
12
  result.each { |e| assert e.frozen? }
13
13
  end
14
+
15
+ def test_unique
16
+ generator = Object.new
17
+ generator.extend FFaker::ModuleUtils
18
+ # returns [1 1 2 2 1 1 2 2 ..][call_index]
19
+ def generator.test
20
+ index = Thread.current[:test_unique] ||= 0
21
+ Thread.current[:test_unique] = (index > 2 ? 0 : index + 1)
22
+ (index / 2) + 1
23
+ end
24
+
25
+ assert_equal(1, generator.unique.test)
26
+ assert_equal(2, generator.unique.test)
27
+
28
+ Thread.new do
29
+ assert_equal(1, generator.unique.test)
30
+ assert_equal(2, generator.unique.test)
31
+
32
+ assert_raises FFaker::UniqueUtils::RetryLimitExceeded do
33
+ generator.unique.test
34
+ end
35
+
36
+ generator.unique.clear
37
+ generator.unique.test
38
+ end.join
39
+
40
+ assert_raises FFaker::UniqueUtils::RetryLimitExceeded do
41
+ generator.unique.test
42
+ end
43
+
44
+ FFaker::UniqueUtils.clear
45
+ generator.unique.test
46
+ end
14
47
  end
data/test/test_name_da.rb CHANGED
@@ -10,7 +10,7 @@ class TestFakerNameDA < Test::Unit::TestCase
10
10
  :any_name, :male_name, :female_name, :last_name, :prefix
11
11
  )
12
12
 
13
- RU_REGEX = /[А-Я][а-я]+/.freeze
13
+ RU_REGEX = /[А-Я][а-я]+/
14
14
 
15
15
  def setup
16
16
  @tester = FFaker::NameDA
data/test/test_name_ph.rb CHANGED
@@ -5,7 +5,7 @@ require_relative 'helper'
5
5
  class TestFakerNamePH < Test::Unit::TestCase
6
6
  include DeterministicHelper
7
7
 
8
- PH_REGEXP = /\A([\wñÑú-]+\.? ?){2,5}\z/.freeze
8
+ PH_REGEXP = /\A([\wñÑú-]+\.? ?){2,5}\z/
9
9
 
10
10
  assert_methods_are_deterministic(
11
11
  FFaker::NamePH,
data/test/test_name_ru.rb CHANGED
@@ -5,8 +5,8 @@ require_relative 'helper'
5
5
  class TestNameRU < Test::Unit::TestCase
6
6
  include DeterministicHelper
7
7
 
8
- RU_REGEX = /\A[а-яА-Я]{2,}\z/.freeze
9
- RU_REGEX_MULTIPLE_WORDS = /\A[а-яА-Я\s]+\z/.freeze
8
+ RU_REGEX = /\A[а-яА-Я]{2,}\z/
9
+ RU_REGEX_MULTIPLE_WORDS = /\A[а-яА-Я\s]+\z/
10
10
 
11
11
  assert_methods_are_deterministic(
12
12
  FFaker::NameRU,
data/test/test_name_ua.rb CHANGED
@@ -15,8 +15,8 @@ class TestNameUA < Test::Unit::TestCase
15
15
  def setup
16
16
  @tester = FFaker::NameUA
17
17
 
18
- @single_word_name_regexp = /\A[а-яА-ЯіїєґІЇЄҐ’\-]+\z/.freeze
19
- @multiple_words_name_regexp = /\A[а-яА-ЯіїєґІЇЄҐ’\-\s]+\z/.freeze
18
+ @single_word_name_regexp = /\A[а-яА-ЯіїєґІЇЄҐ’-]+\z/
19
+ @multiple_words_name_regexp = /\A[а-яА-ЯіїєґІЇЄҐ’\-\s]+\z/
20
20
  end
21
21
 
22
22
  def test_first_name_male
data/test/test_number.rb CHANGED
@@ -5,7 +5,7 @@ require_relative 'helper'
5
5
  class TestNumber < Test::Unit::TestCase
6
6
  include DeterministicHelper
7
7
 
8
- assert_methods_are_deterministic(FFaker::Number, :number, :decimal)
8
+ assert_methods_are_deterministic(FFaker::Number, :number, :decimal, :between)
9
9
 
10
10
  def setup
11
11
  @tester = FFaker::Number
@@ -42,4 +42,16 @@ class TestNumber < Test::Unit::TestCase
42
42
  @tester.decimal(fractional_digits: 0)
43
43
  end
44
44
  end
45
+
46
+ def test_between
47
+ from = -50
48
+ to = 50
49
+ assert_random_between(from..to) { @tester.between(from: from, to: to) }
50
+ assert_instance_of Integer, @tester.between(from: from, to: to)
51
+
52
+ from = -50.0
53
+ to = 50.0
54
+ assert_random_between(from..to) { @tester.between(from: from, to: to) }
55
+ assert_instance_of Float, @tester.between(from: from, to: to)
56
+ end
45
57
  end
@@ -24,7 +24,7 @@ class TestPhoneNumberNL < Test::Unit::TestCase
24
24
 
25
25
  def test_phone_number
26
26
  10.times do
27
- assert_match(/^0([\s\-]*\d){9}$/, @tester.phone_number)
27
+ assert_match(/^0([\s-]*\d){9}$/, @tester.phone_number)
28
28
  end
29
29
  end
30
30
 
@@ -16,7 +16,7 @@ class TestPhoneNumberSE < Test::Unit::TestCase
16
16
  @tester = FFaker::PhoneNumberSE
17
17
  end
18
18
 
19
- ALLOWED_CHARS = /[()\d +-]/.freeze
19
+ ALLOWED_CHARS = /[()\d +-]/
20
20
 
21
21
  def test_mobile_phone_prefix
22
22
  assert FFaker::PhoneNumberSE::MOBILE_PHONE_PREFIX.include?(@tester.mobile_prefix)
@@ -17,36 +17,36 @@ class TestPhoneNumberSG < Test::Unit::TestCase
17
17
  end
18
18
 
19
19
  def test_voip_number
20
- assert_match(/3\d{3}\s\d{4}/, @tester.voip_number)
20
+ assert_match(/\A3\d{3}\s\d{4}\z/, @tester.voip_number)
21
21
  end
22
22
 
23
23
  def test_fixed_line_number
24
- assert_match(/6\d{3}\s\d{4}/, @tester.fixed_line_number)
24
+ assert_match(/\A6\d{3}\s\d{4}\z/, @tester.fixed_line_number)
25
25
  end
26
26
 
27
27
  def test_mobile_number
28
- assert_match(/8\d{3}\s\d{4}/, @tester.mobile_number)
28
+ assert_match(/\A8\d{3}\s\d{4}\z/, @tester.mobile_number)
29
29
  end
30
30
 
31
31
  def test_mobile_or_pager_number
32
- assert_match(/9\d{3}\s\d{4}/, @tester.mobile_or_pager_number)
32
+ assert_match(/\A9\d{3}\s\d{4}\z/, @tester.mobile_or_pager_number)
33
33
  end
34
34
 
35
35
  def test_international_toll_free_number
36
- assert_match(/800\s\d{3}\s\d{4}/, @tester.international_toll_free_number)
36
+ assert_match(/\A800\s\d{3}\s\d{4}\z/, @tester.international_toll_free_number)
37
37
  end
38
38
 
39
39
  def test_toll_free_number
40
- assert_match(/1800\s\d{3}\s\d{4}/, @tester.toll_free_number)
40
+ assert_match(/\A1800\s\d{3}\s\d{4}\z/, @tester.toll_free_number)
41
41
  end
42
42
 
43
43
  def test_premium_service_number
44
- assert_match(/1900\s\d{3}\s\d{4}/, @tester.premium_service_number)
44
+ assert_match(/\A1900\s\d{3}\s\d{4}\z/, @tester.premium_service_number)
45
45
  end
46
46
 
47
47
  def test_phone_number
48
48
  10.times do
49
- assert_match(/[6,8,9]\d{3}\s\d{4}/, @tester.phone_number)
49
+ assert_match(/\A[689]\d{3}\s\d{4}\z/, @tester.phone_number)
50
50
  end
51
51
  end
52
52
  end
@@ -39,16 +39,40 @@ class TestUniqueUtils < Test::Unit::TestCase
39
39
  unique_object.test
40
40
  end
41
41
 
42
- FFaker::UniqueUtils.clear
42
+ unique_object.clear
43
43
 
44
44
  assert_equal(1, unique_object.test)
45
+ end
45
46
 
46
- assert_raises FFaker::UniqueUtils::RetryLimitExceeded do
47
- unique_object.test
47
+ def test_clears_all_unique_values
48
+ stubbed_generator = Object.new
49
+ def stubbed_generator.test
50
+ 1
51
+ end
52
+ other_stubbed_generator = Object.new
53
+ def other_stubbed_generator.test
54
+ 1
48
55
  end
49
56
 
50
- unique_object.clear
57
+ unique_object = FFaker::UniqueUtils.add_instance(stubbed_generator, 3)
58
+ other_unique_object = FFaker::UniqueUtils.add_instance(other_stubbed_generator, 3)
51
59
 
52
- assert_equal(1, unique_object.test)
60
+ [unique_object, other_unique_object].each do |tested_unique_object|
61
+ assert_equal(1, tested_unique_object.test)
62
+
63
+ assert_raises FFaker::UniqueUtils::RetryLimitExceeded do
64
+ tested_unique_object.test
65
+ end
66
+ end
67
+
68
+ FFaker::UniqueUtils.clear
69
+
70
+ [unique_object, other_unique_object].each do |tested_unique_object|
71
+ assert_equal(1, tested_unique_object.test)
72
+ end
73
+ end
74
+
75
+ def test_generates_unique_numbers
76
+ assert_nothing_raised { FFaker::Number.unique.number(digits: 1) }
53
77
  end
54
78
  end
data/test/test_units.rb CHANGED
@@ -13,25 +13,25 @@ class TestUnits < Test::Unit::TestCase
13
13
 
14
14
  def setup
15
15
  @tester = FFaker::Unit
16
- @time_units = @tester::TIME_UNITS.map { |u| OpenStruct.new u }
17
- @temperature_units = @tester::TEMPERATURE_UNITS.map { |u| OpenStruct.new u }
16
+ @time_units = @tester::TIME_UNITS
17
+ @temperature_units = @tester::TEMPERATURE_UNITS
18
18
  end
19
19
 
20
20
  def test_time_name
21
- assert_include @time_units.map(&:name), @tester.time_name
21
+ assert_include @time_units.map { |unit| unit[:name] }, @tester.time_name
22
22
  end
23
23
 
24
24
  def test_time_abbr
25
- assert_include @time_units.map(&:abbreviation), @tester.time_abbr
25
+ assert_include @time_units.map { |unit| unit[:abbreviation] }, @tester.time_abbr
26
26
  end
27
27
 
28
28
  def test_temperature_name
29
- assert_include @temperature_units.map(&:name), @tester.temperature_name
29
+ assert_include @temperature_units.map { |unit| unit[:name] }, @tester.temperature_name
30
30
  end
31
31
 
32
32
  def test_temperature_abbr
33
33
  assert_include \
34
- @temperature_units.map(&:abbreviation),
34
+ @temperature_units.map { |unit| unit[:abbreviation] },
35
35
  @tester.temperature_abbr
36
36
  end
37
37
  end
@@ -14,50 +14,50 @@ class TestUnitsEnglish < Test::Unit::TestCase
14
14
 
15
15
  def setup
16
16
  @tester = FFaker::UnitEnglish
17
- @length_units = @tester::LENGTH_UNITS.map { |u| OpenStruct.new u }
18
- @mass_units = @tester::MASS_UNITS.map { |u| OpenStruct.new u }
19
- @liquid_units = @tester::LIQUID_UNITS.map { |u| OpenStruct.new u }
20
- @volume_units = @tester::VOLUME_UNITS.map { |u| OpenStruct.new u }
21
- @area_units = @tester::AREA_UNITS.map { |u| OpenStruct.new u }
17
+ @length_units = @tester::LENGTH_UNITS
18
+ @mass_units = @tester::MASS_UNITS
19
+ @liquid_units = @tester::LIQUID_UNITS
20
+ @volume_units = @tester::VOLUME_UNITS
21
+ @area_units = @tester::AREA_UNITS
22
22
  end
23
23
 
24
24
  def test_length_name
25
- assert_include @length_units.map(&:name), @tester.length_name
25
+ assert_include @length_units.map { |unit| unit[:name] }, @tester.length_name
26
26
  end
27
27
 
28
28
  def test_length_abbrev
29
- assert_include @length_units.map(&:abbreviation), @tester.length_abbr
29
+ assert_include @length_units.map { |unit| unit[:abbreviation] }, @tester.length_abbr
30
30
  end
31
31
 
32
32
  def test_mass_name
33
- assert_include @mass_units.map(&:name), @tester.mass_name
33
+ assert_include @mass_units.map { |unit| unit[:name] }, @tester.mass_name
34
34
  end
35
35
 
36
36
  def test_mass_abbr
37
- assert_include @mass_units.map(&:abbreviation), @tester.mass_abbr
37
+ assert_include @mass_units.map { |unit| unit[:abbreviation] }, @tester.mass_abbr
38
38
  end
39
39
 
40
40
  def test_liquid_name
41
- assert_include @liquid_units.map(&:name), @tester.liquid_name
41
+ assert_include @liquid_units.map { |unit| unit[:name] }, @tester.liquid_name
42
42
  end
43
43
 
44
44
  def test_liquid_abbr
45
- assert_include @liquid_units.map(&:abbreviation), @tester.liquid_abbr
45
+ assert_include @liquid_units.map { |unit| unit[:abbreviation] }, @tester.liquid_abbr
46
46
  end
47
47
 
48
48
  def test_volume_name
49
- assert_include @volume_units.map(&:name), @tester.volume_name
49
+ assert_include @volume_units.map { |unit| unit[:name] }, @tester.volume_name
50
50
  end
51
51
 
52
52
  def test_volume_abbr
53
- assert_include @volume_units.map(&:abbreviation), @tester.volume_abbr
53
+ assert_include @volume_units.map { |unit| unit[:abbreviation] }, @tester.volume_abbr
54
54
  end
55
55
 
56
56
  def test_area_name
57
- assert_include @area_units.map(&:name), @tester.area_name
57
+ assert_include @area_units.map { |unit| unit[:name] }, @tester.area_name
58
58
  end
59
59
 
60
60
  def test_area_abbr
61
- assert_include @area_units.map(&:abbreviation), @tester.area_abbr
61
+ assert_include @area_units.map { |unit| unit[:abbreviation] }, @tester.area_abbr
62
62
  end
63
63
  end
@@ -14,50 +14,50 @@ class TestUnitsMetric < Test::Unit::TestCase
14
14
 
15
15
  def setup
16
16
  @tester = FFaker::UnitMetric
17
- @length_units = @tester::LENGTH_UNITS.map { |u| OpenStruct.new u }
18
- @mass_units = @tester::MASS_UNITS.map { |u| OpenStruct.new u }
19
- @liquid_units = @tester::LIQUID_UNITS.map { |u| OpenStruct.new u }
20
- @volume_units = @tester::VOLUME_UNITS.map { |u| OpenStruct.new u }
21
- @area_units = @tester::AREA_UNITS.map { |u| OpenStruct.new u }
17
+ @length_units = @tester::LENGTH_UNITS
18
+ @mass_units = @tester::MASS_UNITS
19
+ @liquid_units = @tester::LIQUID_UNITS
20
+ @volume_units = @tester::VOLUME_UNITS
21
+ @area_units = @tester::AREA_UNITS
22
22
  end
23
23
 
24
24
  def test_length_name
25
- assert_include @length_units.map(&:name), @tester.length_name
25
+ assert_include @length_units.map { |unit| unit[:name] }, @tester.length_name
26
26
  end
27
27
 
28
28
  def test_length_abbrev
29
- assert_include @length_units.map(&:abbreviation), @tester.length_abbr
29
+ assert_include @length_units.map { |unit| unit[:abbreviation] }, @tester.length_abbr
30
30
  end
31
31
 
32
32
  def test_mass_name
33
- assert_include @mass_units.map(&:name), @tester.mass_name
33
+ assert_include @mass_units.map { |unit| unit[:name] }, @tester.mass_name
34
34
  end
35
35
 
36
36
  def test_mass_abbr
37
- assert_include @mass_units.map(&:abbreviation), @tester.mass_abbr
37
+ assert_include @mass_units.map { |unit| unit[:abbreviation] }, @tester.mass_abbr
38
38
  end
39
39
 
40
40
  def test_liquid_name
41
- assert_include @liquid_units.map(&:name), @tester.liquid_name
41
+ assert_include @liquid_units.map { |unit| unit[:name] }, @tester.liquid_name
42
42
  end
43
43
 
44
44
  def test_liquid_abbr
45
- assert_include @liquid_units.map(&:abbreviation), @tester.liquid_abbr
45
+ assert_include @liquid_units.map { |unit| unit[:abbreviation] }, @tester.liquid_abbr
46
46
  end
47
47
 
48
48
  def test_volume_name
49
- assert_include @volume_units.map(&:name), @tester.volume_name
49
+ assert_include @volume_units.map { |unit| unit[:name] }, @tester.volume_name
50
50
  end
51
51
 
52
52
  def test_volume_abbr
53
- assert_include @volume_units.map(&:abbreviation), @tester.volume_abbr
53
+ assert_include @volume_units.map { |unit| unit[:abbreviation] }, @tester.volume_abbr
54
54
  end
55
55
 
56
56
  def test_area_name
57
- assert_include @area_units.map(&:name), @tester.area_name
57
+ assert_include @area_units.map { |unit| unit[:name] }, @tester.area_name
58
58
  end
59
59
 
60
60
  def test_area_abbr
61
- assert_include @area_units.map(&:abbreviation), @tester.area_abbr
61
+ assert_include @area_units.map { |unit| unit[:abbreviation] }, @tester.area_abbr
62
62
  end
63
63
  end
data/test/test_vehicle.rb CHANGED
@@ -5,6 +5,14 @@ require_relative 'helper'
5
5
  class TestVehicle < Test::Unit::TestCase
6
6
  include DeterministicHelper
7
7
 
8
+ # https://en.wikibooks.org/wiki/Vehicle_Identification_Numbers_(VIN_codes)/Check_digit
9
+ VIN_TRANSLITERATION_VALUES = {
10
+ 'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8,
11
+ 'J' => 1, 'K' => 2, 'L' => 3, 'M' => 4, 'N' => 5, 'P' => 7, 'R' => 9,
12
+ 'S' => 2, 'T' => 3, 'U' => 4, 'V' => 5, 'W' => 6, 'X' => 7, 'Y' => 8, 'Z' => 9
13
+ }.freeze
14
+ VIN_POSITION_WEIGHTS = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2].freeze
15
+
8
16
  assert_methods_are_deterministic(
9
17
  FFaker::Vehicle,
10
18
  :base_color, :drivetrain, :engine_cylinders, :engine_displacement,
@@ -47,6 +55,7 @@ class TestVehicle < Test::Unit::TestCase
47
55
  assert_not_match(/[IOQ]/, vin) # VINs can't have these letters
48
56
  assert_includes(FFaker::Vehicle::VIN::VALID_ALPHA, vin[6]) # passenger vehicle designator
49
57
  assert_includes(FFaker::Vehicle::VIN::VALID_YEAR_CHARS, vin[9]) # check year character
58
+ assert_equal(vin_checksum_digit(vin), vin[8])
50
59
  end
51
60
 
52
61
  def test_drivetrain
@@ -76,4 +85,17 @@ class TestVehicle < Test::Unit::TestCase
76
85
  def test_interior_upholstery
77
86
  assert_match(/\A[ a-z0-9]+\z/i, FFaker::Vehicle.interior_upholstery)
78
87
  end
88
+
89
+ private
90
+
91
+ def vin_checksum_digit(vin)
92
+ weighted_sum = vin.chars.each_with_index.sum do |char, idx|
93
+ (VIN_TRANSLITERATION_VALUES[char] || char).to_i * VIN_POSITION_WEIGHTS[idx]
94
+ end
95
+
96
+ check_digit = weighted_sum % 11
97
+ check_digit == '10' ? 'X' : check_digit
98
+ check_digit = 'X' if check_digit == 10
99
+ check_digit.to_s
100
+ end
79
101
  end