hash_validator 1.2.0 → 2.0.1

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +6 -1
  3. data/.rubocop.yml +340 -0
  4. data/Gemfile +3 -1
  5. data/README.md +175 -13
  6. data/Rakefile +6 -4
  7. data/hash_validator.gemspec +11 -5
  8. data/lib/hash_validator/base.rb +2 -0
  9. data/lib/hash_validator/configuration.rb +18 -0
  10. data/lib/hash_validator/validations/many.rb +2 -0
  11. data/lib/hash_validator/validations/multiple.rb +2 -0
  12. data/lib/hash_validator/validations/optional.rb +2 -0
  13. data/lib/hash_validator/validations.rb +5 -3
  14. data/lib/hash_validator/validators/alpha_validator.rb +8 -14
  15. data/lib/hash_validator/validators/alphanumeric_validator.rb +8 -14
  16. data/lib/hash_validator/validators/array_validator.rb +45 -49
  17. data/lib/hash_validator/validators/base.rb +31 -4
  18. data/lib/hash_validator/validators/boolean_validator.rb +6 -6
  19. data/lib/hash_validator/validators/class_validator.rb +4 -2
  20. data/lib/hash_validator/validators/digits_validator.rb +8 -14
  21. data/lib/hash_validator/validators/dynamic_func_validator.rb +26 -0
  22. data/lib/hash_validator/validators/dynamic_pattern_validator.rb +25 -0
  23. data/lib/hash_validator/validators/email_validator.rb +8 -8
  24. data/lib/hash_validator/validators/enumerable_validator.rb +8 -8
  25. data/lib/hash_validator/validators/hash_validator.rb +7 -5
  26. data/lib/hash_validator/validators/hex_color_validator.rb +8 -14
  27. data/lib/hash_validator/validators/ip_validator.rb +24 -0
  28. data/lib/hash_validator/validators/ipv4_validator.rb +20 -0
  29. data/lib/hash_validator/validators/ipv6_validator.rb +24 -0
  30. data/lib/hash_validator/validators/json_validator.rb +9 -14
  31. data/lib/hash_validator/validators/lambda_validator.rb +9 -10
  32. data/lib/hash_validator/validators/many_validator.rb +6 -4
  33. data/lib/hash_validator/validators/multiple_validator.rb +5 -3
  34. data/lib/hash_validator/validators/optional_validator.rb +4 -2
  35. data/lib/hash_validator/validators/presence_validator.rb +8 -8
  36. data/lib/hash_validator/validators/regex_validator.rb +8 -8
  37. data/lib/hash_validator/validators/simple_type_validators.rb +4 -2
  38. data/lib/hash_validator/validators/simple_validator.rb +4 -4
  39. data/lib/hash_validator/validators/url_validator.rb +9 -14
  40. data/lib/hash_validator/validators.rb +63 -25
  41. data/lib/hash_validator/version.rb +3 -1
  42. data/lib/hash_validator.rb +7 -4
  43. data/spec/configuration_spec.rb +191 -0
  44. data/spec/hash_validator_spec.rb +135 -116
  45. data/spec/hash_validator_spec_helper.rb +2 -0
  46. data/spec/spec_helper.rb +14 -4
  47. data/spec/validators/alpha_validator_spec.rb +43 -41
  48. data/spec/validators/alphanumeric_validator_spec.rb +44 -42
  49. data/spec/validators/array_spec.rb +102 -47
  50. data/spec/validators/base_spec.rb +25 -10
  51. data/spec/validators/boolean_spec.rb +15 -13
  52. data/spec/validators/class_spec.rb +20 -18
  53. data/spec/validators/digits_validator_spec.rb +46 -44
  54. data/spec/validators/dynamic_func_validator_spec.rb +254 -0
  55. data/spec/validators/dynamic_pattern_validator_spec.rb +152 -0
  56. data/spec/validators/email_spec.rb +15 -13
  57. data/spec/validators/hash_validator_spec.rb +39 -37
  58. data/spec/validators/hex_color_validator_spec.rb +49 -47
  59. data/spec/validators/in_enumerable_spec.rb +32 -30
  60. data/spec/validators/ip_validator_spec.rb +107 -0
  61. data/spec/validators/ipv4_validator_spec.rb +101 -0
  62. data/spec/validators/ipv6_validator_spec.rb +101 -0
  63. data/spec/validators/json_validator_spec.rb +38 -36
  64. data/spec/validators/lambda_spec.rb +20 -18
  65. data/spec/validators/many_spec.rb +25 -23
  66. data/spec/validators/multiple_spec.rb +13 -11
  67. data/spec/validators/optional_spec.rb +22 -20
  68. data/spec/validators/presence_spec.rb +16 -14
  69. data/spec/validators/regexp_spec.rb +14 -12
  70. data/spec/validators/simple_spec.rb +17 -15
  71. data/spec/validators/simple_types_spec.rb +21 -19
  72. data/spec/validators/url_validator_spec.rb +34 -32
  73. data/spec/validators/user_defined_spec.rb +31 -29
  74. metadata +77 -3
  75. data/Plan.md +0 -309
@@ -1,6 +1,8 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- describe 'ActionController::Parameters support' do
3
+ require "spec_helper"
4
+
5
+ describe "ActionController::Parameters support" do
4
6
  # Mock ActionController::Parameters for testing
5
7
  let(:mock_params_class) do
6
8
  Class.new do
@@ -23,12 +25,12 @@ describe 'ActionController::Parameters support' do
23
25
  end
24
26
 
25
27
  def is_a?(klass)
26
- return true if klass.name == 'ActionController::Parameters'
28
+ return true if klass.name == "ActionController::Parameters"
27
29
  super
28
30
  end
29
31
 
30
32
  def class
31
- OpenStruct.new(name: 'ActionController::Parameters')
33
+ Struct.new(:name).new("ActionController::Parameters")
32
34
  end
33
35
  end
34
36
  end
@@ -41,62 +43,62 @@ describe 'ActionController::Parameters support' do
41
43
  end
42
44
  end
43
45
 
44
- it 'should validate ActionController::Parameters objects' do
45
- params = ActionController::Parameters.new({ name: 'John', age: 30 })
46
- validations = { name: 'string', age: 'integer' }
47
-
46
+ it "should validate ActionController::Parameters objects" do
47
+ params = ActionController::Parameters.new({ name: "John", age: 30 })
48
+ validations = { name: "string", age: "integer" }
49
+
48
50
  validator = HashValidator.validate(params, validations)
49
-
51
+
50
52
  expect(validator.valid?).to be true
51
53
  expect(validator.errors).to be_empty
52
54
  end
53
55
 
54
- it 'should handle nested ActionController::Parameters' do
55
- nested_params = ActionController::Parameters.new({ theme: 'dark' })
56
- params = ActionController::Parameters.new({
57
- name: 'John',
56
+ it "should handle nested ActionController::Parameters" do
57
+ nested_params = ActionController::Parameters.new({ theme: "dark" })
58
+ params = ActionController::Parameters.new({
59
+ name: "John",
58
60
  preferences: nested_params
59
61
  })
60
-
61
- validations = {
62
- name: 'string',
63
- preferences: { theme: 'string' }
62
+
63
+ validations = {
64
+ name: "string",
65
+ preferences: { theme: "string" }
64
66
  }
65
-
67
+
66
68
  validator = HashValidator.validate(params, validations)
67
-
69
+
68
70
  expect(validator.valid?).to be true
69
71
  expect(validator.errors).to be_empty
70
72
  end
71
73
 
72
- it 'should validate ActionController::Parameters with our new validators' do
74
+ it "should validate ActionController::Parameters with our new validators" do
73
75
  params = ActionController::Parameters.new({
74
- name: 'John',
75
- email: 'john@example.com',
76
- website: 'https://john.com',
77
- zip_code: '12345'
76
+ name: "John",
77
+ email: "john@example.com",
78
+ website: "https://john.com",
79
+ zip_code: "12345"
78
80
  })
79
-
81
+
80
82
  validations = {
81
- name: 'alpha',
82
- email: 'email',
83
- website: 'url',
84
- zip_code: 'digits'
83
+ name: "alpha",
84
+ email: "email",
85
+ website: "url",
86
+ zip_code: "digits"
85
87
  }
86
-
88
+
87
89
  validator = HashValidator.validate(params, validations)
88
-
90
+
89
91
  expect(validator.valid?).to be true
90
92
  expect(validator.errors).to be_empty
91
93
  end
92
94
 
93
- it 'should still work with regular hashes' do
94
- hash = { name: 'John', age: 30 }
95
- validations = { name: 'string', age: 'integer' }
96
-
95
+ it "should still work with regular hashes" do
96
+ hash = { name: "John", age: 30 }
97
+ validations = { name: "string", age: "integer" }
98
+
97
99
  validator = HashValidator.validate(hash, validations)
98
-
100
+
99
101
  expect(validator.valid?).to be true
100
102
  expect(validator.errors).to be_empty
101
103
  end
102
- end
104
+ end
@@ -1,111 +1,113 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  describe HashValidator::Validator::HexColorValidator do
4
6
  let(:validator) { HashValidator::Validator::HexColorValidator.new }
5
7
 
6
- context 'valid hex colors' do
7
- it 'validates 6-digit hex colors (lowercase)' do
8
+ context "valid hex colors" do
9
+ it "validates 6-digit hex colors (lowercase)" do
8
10
  errors = {}
9
- validator.validate('key', '#ff0000', {}, errors)
11
+ validator.validate("key", "#ff0000", {}, errors)
10
12
  expect(errors).to be_empty
11
13
  end
12
14
 
13
- it 'validates 6-digit hex colors (uppercase)' do
15
+ it "validates 6-digit hex colors (uppercase)" do
14
16
  errors = {}
15
- validator.validate('key', '#FF0000', {}, errors)
17
+ validator.validate("key", "#FF0000", {}, errors)
16
18
  expect(errors).to be_empty
17
19
  end
18
20
 
19
- it 'validates 6-digit hex colors (mixed case)' do
21
+ it "validates 6-digit hex colors (mixed case)" do
20
22
  errors = {}
21
- validator.validate('key', '#Ff0000', {}, errors)
23
+ validator.validate("key", "#Ff0000", {}, errors)
22
24
  expect(errors).to be_empty
23
25
  end
24
26
 
25
- it 'validates 3-digit hex colors (lowercase)' do
27
+ it "validates 3-digit hex colors (lowercase)" do
26
28
  errors = {}
27
- validator.validate('key', '#f00', {}, errors)
29
+ validator.validate("key", "#f00", {}, errors)
28
30
  expect(errors).to be_empty
29
31
  end
30
32
 
31
- it 'validates 3-digit hex colors (uppercase)' do
33
+ it "validates 3-digit hex colors (uppercase)" do
32
34
  errors = {}
33
- validator.validate('key', '#F00', {}, errors)
35
+ validator.validate("key", "#F00", {}, errors)
34
36
  expect(errors).to be_empty
35
37
  end
36
38
 
37
- it 'validates black color' do
39
+ it "validates black color" do
38
40
  errors = {}
39
- validator.validate('key', '#000000', {}, errors)
41
+ validator.validate("key", "#000000", {}, errors)
40
42
  expect(errors).to be_empty
41
43
  end
42
44
 
43
- it 'validates white color' do
45
+ it "validates white color" do
44
46
  errors = {}
45
- validator.validate('key', '#ffffff', {}, errors)
47
+ validator.validate("key", "#ffffff", {}, errors)
46
48
  expect(errors).to be_empty
47
49
  end
48
50
 
49
- it 'validates complex hex colors' do
51
+ it "validates complex hex colors" do
50
52
  errors = {}
51
- validator.validate('key', '#3a7bd4', {}, errors)
53
+ validator.validate("key", "#3a7bd4", {}, errors)
52
54
  expect(errors).to be_empty
53
55
  end
54
56
  end
55
57
 
56
- context 'invalid hex colors' do
57
- it 'rejects non-string values' do
58
+ context "invalid hex colors" do
59
+ it "rejects non-string values" do
58
60
  errors = {}
59
- validator.validate('key', 123, {}, errors)
60
- expect(errors['key']).to eq('is not a valid hex color')
61
+ validator.validate("key", 123, {}, errors)
62
+ expect(errors["key"]).to eq("is not a valid hex color")
61
63
  end
62
64
 
63
- it 'rejects nil values' do
65
+ it "rejects nil values" do
64
66
  errors = {}
65
- validator.validate('key', nil, {}, errors)
66
- expect(errors['key']).to eq('is not a valid hex color')
67
+ validator.validate("key", nil, {}, errors)
68
+ expect(errors["key"]).to eq("is not a valid hex color")
67
69
  end
68
70
 
69
- it 'rejects hex colors without hash' do
71
+ it "rejects hex colors without hash" do
70
72
  errors = {}
71
- validator.validate('key', 'ff0000', {}, errors)
72
- expect(errors['key']).to eq('is not a valid hex color')
73
+ validator.validate("key", "ff0000", {}, errors)
74
+ expect(errors["key"]).to eq("is not a valid hex color")
73
75
  end
74
76
 
75
- it 'rejects invalid length (4 digits)' do
77
+ it "rejects invalid length (4 digits)" do
76
78
  errors = {}
77
- validator.validate('key', '#ff00', {}, errors)
78
- expect(errors['key']).to eq('is not a valid hex color')
79
+ validator.validate("key", "#ff00", {}, errors)
80
+ expect(errors["key"]).to eq("is not a valid hex color")
79
81
  end
80
82
 
81
- it 'rejects invalid length (5 digits)' do
83
+ it "rejects invalid length (5 digits)" do
82
84
  errors = {}
83
- validator.validate('key', '#ff000', {}, errors)
84
- expect(errors['key']).to eq('is not a valid hex color')
85
+ validator.validate("key", "#ff000", {}, errors)
86
+ expect(errors["key"]).to eq("is not a valid hex color")
85
87
  end
86
88
 
87
- it 'rejects invalid length (7 digits)' do
89
+ it "rejects invalid length (7 digits)" do
88
90
  errors = {}
89
- validator.validate('key', '#ff00000', {}, errors)
90
- expect(errors['key']).to eq('is not a valid hex color')
91
+ validator.validate("key", "#ff00000", {}, errors)
92
+ expect(errors["key"]).to eq("is not a valid hex color")
91
93
  end
92
94
 
93
- it 'rejects invalid characters' do
95
+ it "rejects invalid characters" do
94
96
  errors = {}
95
- validator.validate('key', '#gg0000', {}, errors)
96
- expect(errors['key']).to eq('is not a valid hex color')
97
+ validator.validate("key", "#gg0000", {}, errors)
98
+ expect(errors["key"]).to eq("is not a valid hex color")
97
99
  end
98
100
 
99
- it 'rejects empty strings' do
101
+ it "rejects empty strings" do
100
102
  errors = {}
101
- validator.validate('key', '', {}, errors)
102
- expect(errors['key']).to eq('is not a valid hex color')
103
+ validator.validate("key", "", {}, errors)
104
+ expect(errors["key"]).to eq("is not a valid hex color")
103
105
  end
104
106
 
105
- it 'rejects just hash symbol' do
107
+ it "rejects just hash symbol" do
106
108
  errors = {}
107
- validator.validate('key', '#', {}, errors)
108
- expect(errors['key']).to eq('is not a valid hex color')
109
+ validator.validate("key", "#", {}, errors)
110
+ expect(errors["key"]).to eq("is not a valid hex color")
109
111
  end
110
112
  end
111
- end
113
+ end
@@ -1,67 +1,69 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- describe 'Enumerable validator' do
4
- describe 'Accepting Enumerables in validations' do
5
- it 'should accept an empty array' do
3
+ require "spec_helper"
4
+
5
+ describe "Enumerable validator" do
6
+ describe "Accepting Enumerables in validations" do
7
+ it "should accept an empty array" do
6
8
  validate({}, { foo: [] })
7
9
  end
8
10
 
9
- it 'should accept an array' do
10
- validate({}, { foo: [ 'apple', 'banana', 'carrot' ] })
11
+ it "should accept an array" do
12
+ validate({}, { foo: [ "apple", "banana", "carrot" ] })
11
13
  end
12
14
 
13
- it 'should accept a hash' do
14
- validate({}, { foo: { apple: 'apple', banana: 'banana', carrot: 'cattot' } })
15
+ it "should accept a hash" do
16
+ validate({}, { foo: { apple: "apple", banana: "banana", carrot: "cattot" } })
15
17
  end
16
18
  end
17
19
 
18
- describe '#validate' do
19
- describe 'Simple Array' do
20
- let(:validations) {{ fruit: [ 'apple', 'banana', 'carrot' ] }}
20
+ describe "#validate" do
21
+ describe "Simple Array" do
22
+ let(:validations) { { fruit: [ "apple", "banana", "carrot" ] } }
21
23
 
22
- it 'should validate true if the value is present' do
23
- expect(validate({ fruit: 'apple' }, validations).valid?).to eq true
24
+ it "should validate true if the value is present" do
25
+ expect(validate({ fruit: "apple" }, validations).valid?).to eq true
24
26
  end
25
27
 
26
- it 'should validate false if the value is not present' do
27
- expect(validate({ fruit: 'pear' }, validations).valid?).to eq false
28
+ it "should validate false if the value is not present" do
29
+ expect(validate({ fruit: "pear" }, validations).valid?).to eq false
28
30
  end
29
31
 
30
- it 'should validate false if the key is not present' do
31
- expect(validate({ something: 'apple' }, validations).valid?).to eq false
32
+ it "should validate false if the key is not present" do
33
+ expect(validate({ something: "apple" }, validations).valid?).to eq false
32
34
  end
33
35
 
34
- it 'should provide an appropriate error message is the value is not present' do
35
- expect(validate({ fruit: 'pear' }, validations).errors).to eq({ fruit: 'value from list required' })
36
+ it "should provide an appropriate error message is the value is not present" do
37
+ expect(validate({ fruit: "pear" }, validations).errors).to eq({ fruit: "value from list required" })
36
38
  end
37
39
  end
38
40
 
39
- describe 'Range' do
40
- let(:validations) {{ number: 1..10 }}
41
+ describe "Range" do
42
+ let(:validations) { { number: 1..10 } }
41
43
 
42
- it 'should validate true if the value is present' do
44
+ it "should validate true if the value is present" do
43
45
  expect(validate({ number: 5 }, validations).valid?).to eq true
44
46
  end
45
- it 'should validate false if the value is not present' do
47
+ it "should validate false if the value is not present" do
46
48
  expect(validate({ number: 15 }, validations).valid?).to eq false
47
49
  end
48
50
  end
49
51
 
50
- describe 'Infinite Range' do
51
- let(:validations) {{ number: 1..Float::INFINITY }}
52
+ describe "Infinite Range" do
53
+ let(:validations) { { number: 1..Float::INFINITY } }
52
54
 
53
- it 'should validate true if the value is present' do
55
+ it "should validate true if the value is present" do
54
56
  expect(validate({ number: 5 }, validations).valid?).to eq true
55
57
  end
56
- it 'should validate false if the value is not present' do
58
+ it "should validate false if the value is not present" do
57
59
  expect(validate({ number: -5 }, validations).valid?).to eq false
58
60
  end
59
61
  end
60
62
 
61
- describe 'nil values' do
62
- let(:validations) {{ fruit: [ nil, :apple, :banana ] }}
63
+ describe "nil values" do
64
+ let(:validations) { { fruit: [ nil, :apple, :banana ] } }
63
65
 
64
- it 'should validate true if a nil value is present' do
66
+ it "should validate true if a nil value is present" do
65
67
  expect(validate({ fruit: nil }, validations).valid?).to eq true
66
68
  end
67
69
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe HashValidator::Validator::IpValidator do
6
+ let(:validator) { HashValidator::Validator::IpValidator.new }
7
+
8
+ context "valid IP addresses" do
9
+ it "validates IPv4 addresses" do
10
+ errors = {}
11
+ validator.validate("key", "192.168.1.1", {}, errors)
12
+ expect(errors).to be_empty
13
+ end
14
+
15
+ it "validates IPv4 localhost" do
16
+ errors = {}
17
+ validator.validate("key", "127.0.0.1", {}, errors)
18
+ expect(errors).to be_empty
19
+ end
20
+
21
+ it "validates IPv4 zero address" do
22
+ errors = {}
23
+ validator.validate("key", "0.0.0.0", {}, errors)
24
+ expect(errors).to be_empty
25
+ end
26
+
27
+ it "validates IPv4 broadcast address" do
28
+ errors = {}
29
+ validator.validate("key", "255.255.255.255", {}, errors)
30
+ expect(errors).to be_empty
31
+ end
32
+
33
+ it "validates IPv6 addresses" do
34
+ errors = {}
35
+ validator.validate("key", "2001:db8:85a3::8a2e:370:7334", {}, errors)
36
+ expect(errors).to be_empty
37
+ end
38
+
39
+ it "validates IPv6 localhost" do
40
+ errors = {}
41
+ validator.validate("key", "::1", {}, errors)
42
+ expect(errors).to be_empty
43
+ end
44
+
45
+ it "validates IPv6 zero address" do
46
+ errors = {}
47
+ validator.validate("key", "::", {}, errors)
48
+ expect(errors).to be_empty
49
+ end
50
+
51
+ it "validates IPv4-mapped IPv6 addresses" do
52
+ errors = {}
53
+ validator.validate("key", "::ffff:192.168.1.1", {}, errors)
54
+ expect(errors).to be_empty
55
+ end
56
+ end
57
+
58
+ context "invalid IP addresses" do
59
+ it "rejects non-string values" do
60
+ errors = {}
61
+ validator.validate("key", 123, {}, errors)
62
+ expect(errors["key"]).to eq("is not a valid IP address")
63
+ end
64
+
65
+ it "rejects nil values" do
66
+ errors = {}
67
+ validator.validate("key", nil, {}, errors)
68
+ expect(errors["key"]).to eq("is not a valid IP address")
69
+ end
70
+
71
+ it "rejects malformed IPv4 addresses" do
72
+ errors = {}
73
+ validator.validate("key", "256.1.1.1", {}, errors)
74
+ expect(errors["key"]).to eq("is not a valid IP address")
75
+ end
76
+
77
+ it "rejects malformed IPv6 addresses" do
78
+ errors = {}
79
+ validator.validate("key", "2001:db8:85a3::8a2e::7334", {}, errors)
80
+ expect(errors["key"]).to eq("is not a valid IP address")
81
+ end
82
+
83
+ it "rejects non-IP strings" do
84
+ errors = {}
85
+ validator.validate("key", "not an ip", {}, errors)
86
+ expect(errors["key"]).to eq("is not a valid IP address")
87
+ end
88
+
89
+ it "rejects empty strings" do
90
+ errors = {}
91
+ validator.validate("key", "", {}, errors)
92
+ expect(errors["key"]).to eq("is not a valid IP address")
93
+ end
94
+
95
+ it "rejects hostnames" do
96
+ errors = {}
97
+ validator.validate("key", "example.com", {}, errors)
98
+ expect(errors["key"]).to eq("is not a valid IP address")
99
+ end
100
+
101
+ it "rejects URLs" do
102
+ errors = {}
103
+ validator.validate("key", "http://192.168.1.1", {}, errors)
104
+ expect(errors["key"]).to eq("is not a valid IP address")
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe HashValidator::Validator::Ipv4Validator do
6
+ let(:validator) { HashValidator::Validator::Ipv4Validator.new }
7
+
8
+ context "valid IPv4 addresses" do
9
+ it "validates standard IPv4 addresses" do
10
+ errors = {}
11
+ validator.validate("key", "192.168.1.1", {}, errors)
12
+ expect(errors).to be_empty
13
+ end
14
+
15
+ it "validates localhost" do
16
+ errors = {}
17
+ validator.validate("key", "127.0.0.1", {}, errors)
18
+ expect(errors).to be_empty
19
+ end
20
+
21
+ it "validates zero address" do
22
+ errors = {}
23
+ validator.validate("key", "0.0.0.0", {}, errors)
24
+ expect(errors).to be_empty
25
+ end
26
+
27
+ it "validates broadcast address" do
28
+ errors = {}
29
+ validator.validate("key", "255.255.255.255", {}, errors)
30
+ expect(errors).to be_empty
31
+ end
32
+
33
+ it "validates private network addresses" do
34
+ errors = {}
35
+ validator.validate("key", "10.0.0.1", {}, errors)
36
+ expect(errors).to be_empty
37
+ end
38
+
39
+ it "validates Class B private addresses" do
40
+ errors = {}
41
+ validator.validate("key", "172.16.0.1", {}, errors)
42
+ expect(errors).to be_empty
43
+ end
44
+ end
45
+
46
+ context "invalid IPv4 addresses" do
47
+ it "rejects non-string values" do
48
+ errors = {}
49
+ validator.validate("key", 123, {}, errors)
50
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
51
+ end
52
+
53
+ it "rejects nil values" do
54
+ errors = {}
55
+ validator.validate("key", nil, {}, errors)
56
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
57
+ end
58
+
59
+ it "rejects octets over 255" do
60
+ errors = {}
61
+ validator.validate("key", "256.1.1.1", {}, errors)
62
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
63
+ end
64
+
65
+ it "rejects too few octets" do
66
+ errors = {}
67
+ validator.validate("key", "192.168.1", {}, errors)
68
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
69
+ end
70
+
71
+ it "rejects too many octets" do
72
+ errors = {}
73
+ validator.validate("key", "192.168.1.1.1", {}, errors)
74
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
75
+ end
76
+
77
+ it "rejects IPv6 addresses" do
78
+ errors = {}
79
+ validator.validate("key", "2001:db8::1", {}, errors)
80
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
81
+ end
82
+
83
+ it "rejects malformed addresses" do
84
+ errors = {}
85
+ validator.validate("key", "192.168.1.", {}, errors)
86
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
87
+ end
88
+
89
+ it "rejects empty strings" do
90
+ errors = {}
91
+ validator.validate("key", "", {}, errors)
92
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
93
+ end
94
+
95
+ it "rejects non-numeric octets" do
96
+ errors = {}
97
+ validator.validate("key", "192.168.a.1", {}, errors)
98
+ expect(errors["key"]).to eq("is not a valid IPv4 address")
99
+ end
100
+ end
101
+ end