ffaker 2.21.0 → 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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