hash_validator 1.2.0 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +173 -12
- data/lib/hash_validator/configuration.rb +16 -0
- data/lib/hash_validator/validators/alpha_validator.rb +4 -12
- data/lib/hash_validator/validators/alphanumeric_validator.rb +4 -12
- data/lib/hash_validator/validators/array_validator.rb +1 -1
- data/lib/hash_validator/validators/base.rb +28 -3
- data/lib/hash_validator/validators/boolean_validator.rb +3 -5
- data/lib/hash_validator/validators/class_validator.rb +1 -1
- data/lib/hash_validator/validators/digits_validator.rb +4 -12
- data/lib/hash_validator/validators/dynamic_func_validator.rb +26 -0
- data/lib/hash_validator/validators/dynamic_pattern_validator.rb +23 -0
- data/lib/hash_validator/validators/email_validator.rb +4 -6
- data/lib/hash_validator/validators/enumerable_validator.rb +4 -6
- data/lib/hash_validator/validators/hash_validator.rb +2 -2
- data/lib/hash_validator/validators/hex_color_validator.rb +4 -12
- data/lib/hash_validator/validators/ip_validator.rb +22 -0
- data/lib/hash_validator/validators/ipv4_validator.rb +18 -0
- data/lib/hash_validator/validators/ipv6_validator.rb +22 -0
- data/lib/hash_validator/validators/json_validator.rb +4 -11
- data/lib/hash_validator/validators/lambda_validator.rb +5 -8
- data/lib/hash_validator/validators/many_validator.rb +3 -3
- data/lib/hash_validator/validators/multiple_validator.rb +1 -1
- data/lib/hash_validator/validators/optional_validator.rb +1 -1
- data/lib/hash_validator/validators/presence_validator.rb +4 -6
- data/lib/hash_validator/validators/regex_validator.rb +4 -6
- data/lib/hash_validator/validators/simple_type_validators.rb +1 -1
- data/lib/hash_validator/validators/simple_validator.rb +2 -4
- data/lib/hash_validator/validators/url_validator.rb +4 -11
- data/lib/hash_validator/validators.rb +40 -4
- data/lib/hash_validator/version.rb +1 -1
- data/lib/hash_validator.rb +1 -0
- data/spec/configuration_spec.rb +189 -0
- data/spec/hash_validator_spec.rb +4 -4
- data/spec/validators/base_spec.rb +2 -2
- data/spec/validators/dynamic_func_validator_spec.rb +252 -0
- data/spec/validators/dynamic_pattern_validator_spec.rb +150 -0
- data/spec/validators/ip_validator_spec.rb +105 -0
- data/spec/validators/ipv4_validator_spec.rb +99 -0
- data/spec/validators/ipv6_validator_spec.rb +99 -0
- data/spec/validators/user_defined_spec.rb +2 -2
- metadata +20 -3
- data/Plan.md +0 -309
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashValidator::Validator::DynamicFuncValidator do
|
4
|
+
describe 'Function-based validator' do
|
5
|
+
let(:odd_func_validator) do
|
6
|
+
HashValidator::Validator::DynamicFuncValidator.new(
|
7
|
+
'odd_func',
|
8
|
+
->(n) { n.is_a?(Integer) && n.odd? },
|
9
|
+
'is not an odd integer'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:range_validator) do
|
14
|
+
HashValidator::Validator::DynamicFuncValidator.new(
|
15
|
+
'in_range',
|
16
|
+
->(n) { n.is_a?(Numeric) && n >= 18 && n <= 65 },
|
17
|
+
'must be between 18 and 65'
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:custom_validator) do
|
22
|
+
HashValidator::Validator::DynamicFuncValidator.new(
|
23
|
+
'custom',
|
24
|
+
proc { |v| v.to_s.length > 5 },
|
25
|
+
'must be longer than 5 characters'
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:errors) { Hash.new }
|
30
|
+
|
31
|
+
describe '#initialize' do
|
32
|
+
it 'requires a callable object' do
|
33
|
+
expect {
|
34
|
+
HashValidator::Validator::DynamicFuncValidator.new('test', 'not_callable')
|
35
|
+
}.to raise_error(ArgumentError, 'Function must be callable (proc or lambda)')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'accepts a lambda' do
|
39
|
+
validator = HashValidator::Validator::DynamicFuncValidator.new(
|
40
|
+
'test',
|
41
|
+
->(v) { true }
|
42
|
+
)
|
43
|
+
expect(validator.func).to respond_to(:call)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'accepts a proc' do
|
47
|
+
validator = HashValidator::Validator::DynamicFuncValidator.new(
|
48
|
+
'test',
|
49
|
+
proc { |v| true }
|
50
|
+
)
|
51
|
+
expect(validator.func).to respond_to(:call)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'accepts a custom error message' do
|
55
|
+
validator = HashValidator::Validator::DynamicFuncValidator.new(
|
56
|
+
'test',
|
57
|
+
->(v) { true },
|
58
|
+
'custom error'
|
59
|
+
)
|
60
|
+
expect(validator.error_message).to eq('custom error')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'uses default error message when none provided' do
|
64
|
+
validator = HashValidator::Validator::DynamicFuncValidator.new(
|
65
|
+
'test',
|
66
|
+
->(v) { true }
|
67
|
+
)
|
68
|
+
expect(validator.error_message).to eq('test required')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#should_validate?' do
|
73
|
+
it 'validates the correct name' do
|
74
|
+
expect(odd_func_validator.should_validate?('odd_func')).to eq true
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'does not validate other names' do
|
78
|
+
expect(odd_func_validator.should_validate?('even_func')).to eq false
|
79
|
+
expect(odd_func_validator.should_validate?('string')).to eq false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#validate' do
|
84
|
+
context 'with odd number function' do
|
85
|
+
it 'validates odd integers correctly' do
|
86
|
+
odd_func_validator.validate(:key, 1, {}, errors)
|
87
|
+
expect(errors).to be_empty
|
88
|
+
|
89
|
+
errors.clear
|
90
|
+
odd_func_validator.validate(:key, 13, {}, errors)
|
91
|
+
expect(errors).to be_empty
|
92
|
+
|
93
|
+
errors.clear
|
94
|
+
odd_func_validator.validate(:key, -7, {}, errors)
|
95
|
+
expect(errors).to be_empty
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'rejects even integers' do
|
99
|
+
odd_func_validator.validate(:key, 2, {}, errors)
|
100
|
+
expect(errors).to eq({ key: 'is not an odd integer' })
|
101
|
+
|
102
|
+
errors.clear
|
103
|
+
odd_func_validator.validate(:key, 100, {}, errors)
|
104
|
+
expect(errors).to eq({ key: 'is not an odd integer' })
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'rejects non-integers' do
|
108
|
+
odd_func_validator.validate(:key, 1.5, {}, errors)
|
109
|
+
expect(errors).to eq({ key: 'is not an odd integer' })
|
110
|
+
|
111
|
+
errors.clear
|
112
|
+
odd_func_validator.validate(:key, '1', {}, errors)
|
113
|
+
expect(errors).to eq({ key: 'is not an odd integer' })
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'with range validator' do
|
118
|
+
it 'validates numbers in range' do
|
119
|
+
range_validator.validate(:key, 18, {}, errors)
|
120
|
+
expect(errors).to be_empty
|
121
|
+
|
122
|
+
errors.clear
|
123
|
+
range_validator.validate(:key, 30, {}, errors)
|
124
|
+
expect(errors).to be_empty
|
125
|
+
|
126
|
+
errors.clear
|
127
|
+
range_validator.validate(:key, 65, {}, errors)
|
128
|
+
expect(errors).to be_empty
|
129
|
+
|
130
|
+
errors.clear
|
131
|
+
range_validator.validate(:key, 25.5, {}, errors)
|
132
|
+
expect(errors).to be_empty
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'rejects numbers outside range' do
|
136
|
+
range_validator.validate(:key, 17, {}, errors)
|
137
|
+
expect(errors).to eq({ key: 'must be between 18 and 65' })
|
138
|
+
|
139
|
+
errors.clear
|
140
|
+
range_validator.validate(:key, 66, {}, errors)
|
141
|
+
expect(errors).to eq({ key: 'must be between 18 and 65' })
|
142
|
+
|
143
|
+
errors.clear
|
144
|
+
range_validator.validate(:key, -5, {}, errors)
|
145
|
+
expect(errors).to eq({ key: 'must be between 18 and 65' })
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'rejects non-numeric values' do
|
149
|
+
range_validator.validate(:key, 'twenty', {}, errors)
|
150
|
+
expect(errors).to eq({ key: 'must be between 18 and 65' })
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'with custom validator using proc' do
|
155
|
+
it 'validates strings longer than 5 chars' do
|
156
|
+
custom_validator.validate(:key, 'hello world', {}, errors)
|
157
|
+
expect(errors).to be_empty
|
158
|
+
|
159
|
+
errors.clear
|
160
|
+
custom_validator.validate(:key, 'testing', {}, errors)
|
161
|
+
expect(errors).to be_empty
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'rejects strings 5 chars or shorter' do
|
165
|
+
custom_validator.validate(:key, 'hello', {}, errors)
|
166
|
+
expect(errors).to eq({ key: 'must be longer than 5 characters' })
|
167
|
+
|
168
|
+
errors.clear
|
169
|
+
custom_validator.validate(:key, 'hi', {}, errors)
|
170
|
+
expect(errors).to eq({ key: 'must be longer than 5 characters' })
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'converts values to strings' do
|
174
|
+
custom_validator.validate(:key, 123456, {}, errors)
|
175
|
+
expect(errors).to be_empty
|
176
|
+
|
177
|
+
errors.clear
|
178
|
+
custom_validator.validate(:key, 12345, {}, errors)
|
179
|
+
expect(errors).to eq({ key: 'must be longer than 5 characters' })
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'with function that raises errors' do
|
184
|
+
let(:error_func_validator) do
|
185
|
+
HashValidator::Validator::DynamicFuncValidator.new(
|
186
|
+
'error_func',
|
187
|
+
->(v) { raise 'intentional error' },
|
188
|
+
'validation failed'
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'treats exceptions as validation failures' do
|
193
|
+
error_func_validator.validate(:key, 'any value', {}, errors)
|
194
|
+
expect(errors).to eq({ key: 'validation failed' })
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe 'Integration with HashValidator.add_validator' do
|
200
|
+
before do
|
201
|
+
HashValidator.add_validator('adult_age',
|
202
|
+
func: ->(age) { age.is_a?(Integer) && age >= 18 },
|
203
|
+
error_message: 'must be 18 or older')
|
204
|
+
|
205
|
+
HashValidator.add_validator('palindrome',
|
206
|
+
func: proc { |s| s.to_s == s.to_s.reverse },
|
207
|
+
error_message: 'must be a palindrome')
|
208
|
+
end
|
209
|
+
|
210
|
+
after do
|
211
|
+
HashValidator.remove_validator('adult_age')
|
212
|
+
HashValidator.remove_validator('palindrome')
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'can register lambda-based validators' do
|
216
|
+
validator = HashValidator.validate(
|
217
|
+
{ age: 25 },
|
218
|
+
{ age: 'adult_age' }
|
219
|
+
)
|
220
|
+
expect(validator.valid?).to eq true
|
221
|
+
expect(validator.errors).to be_empty
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'returns errors for invalid lambda validations' do
|
225
|
+
validator = HashValidator.validate(
|
226
|
+
{ age: 16 },
|
227
|
+
{ age: 'adult_age' }
|
228
|
+
)
|
229
|
+
expect(validator.valid?).to eq false
|
230
|
+
expect(validator.errors).to eq({ age: 'must be 18 or older' })
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'can register proc-based validators' do
|
234
|
+
validator = HashValidator.validate(
|
235
|
+
{ word: 'racecar' },
|
236
|
+
{ word: 'palindrome' }
|
237
|
+
)
|
238
|
+
expect(validator.valid?).to eq true
|
239
|
+
expect(validator.errors).to be_empty
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'returns errors for invalid proc validations' do
|
243
|
+
validator = HashValidator.validate(
|
244
|
+
{ word: 'hello' },
|
245
|
+
{ word: 'palindrome' }
|
246
|
+
)
|
247
|
+
expect(validator.valid?).to eq false
|
248
|
+
expect(validator.errors).to eq({ word: 'must be a palindrome' })
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashValidator::Validator::DynamicPatternValidator do
|
4
|
+
describe 'Pattern-based validator' do
|
5
|
+
let(:odd_pattern_validator) do
|
6
|
+
HashValidator::Validator::DynamicPatternValidator.new(
|
7
|
+
'odd_pattern',
|
8
|
+
/\A\d*[13579]\z/,
|
9
|
+
'is not an odd number'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:postal_code_validator) do
|
14
|
+
HashValidator::Validator::DynamicPatternValidator.new(
|
15
|
+
'us_postal',
|
16
|
+
/\A\d{5}(-\d{4})?\z/,
|
17
|
+
'is not a valid US postal code'
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:errors) { Hash.new }
|
22
|
+
|
23
|
+
describe '#initialize' do
|
24
|
+
it 'requires a valid regular expression' do
|
25
|
+
expect {
|
26
|
+
HashValidator::Validator::DynamicPatternValidator.new('test', 'not_a_regex')
|
27
|
+
}.to raise_error(ArgumentError, 'Pattern must be a regular expression')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'accepts a custom error message' do
|
31
|
+
validator = HashValidator::Validator::DynamicPatternValidator.new(
|
32
|
+
'test',
|
33
|
+
/test/,
|
34
|
+
'custom error'
|
35
|
+
)
|
36
|
+
expect(validator.error_message).to eq('custom error')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'uses default error message when none provided' do
|
40
|
+
validator = HashValidator::Validator::DynamicPatternValidator.new('test', /test/)
|
41
|
+
expect(validator.error_message).to eq('test required')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#should_validate?' do
|
46
|
+
it 'validates the correct name' do
|
47
|
+
expect(odd_pattern_validator.should_validate?('odd_pattern')).to eq true
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does not validate other names' do
|
51
|
+
expect(odd_pattern_validator.should_validate?('even_pattern')).to eq false
|
52
|
+
expect(odd_pattern_validator.should_validate?('string')).to eq false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#validate' do
|
57
|
+
context 'with odd number pattern' do
|
58
|
+
it 'validates odd numbers correctly' do
|
59
|
+
odd_pattern_validator.validate(:key, '1', {}, errors)
|
60
|
+
expect(errors).to be_empty
|
61
|
+
|
62
|
+
errors.clear
|
63
|
+
odd_pattern_validator.validate(:key, '13', {}, errors)
|
64
|
+
expect(errors).to be_empty
|
65
|
+
|
66
|
+
errors.clear
|
67
|
+
odd_pattern_validator.validate(:key, '999', {}, errors)
|
68
|
+
expect(errors).to be_empty
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'rejects even numbers' do
|
72
|
+
odd_pattern_validator.validate(:key, '2', {}, errors)
|
73
|
+
expect(errors).to eq({ key: 'is not an odd number' })
|
74
|
+
|
75
|
+
errors.clear
|
76
|
+
odd_pattern_validator.validate(:key, '100', {}, errors)
|
77
|
+
expect(errors).to eq({ key: 'is not an odd number' })
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'rejects non-numeric strings' do
|
81
|
+
odd_pattern_validator.validate(:key, 'abc', {}, errors)
|
82
|
+
expect(errors).to eq({ key: 'is not an odd number' })
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'converts non-string values to strings' do
|
86
|
+
odd_pattern_validator.validate(:key, 13, {}, errors)
|
87
|
+
expect(errors).to be_empty
|
88
|
+
|
89
|
+
errors.clear
|
90
|
+
odd_pattern_validator.validate(:key, 14, {}, errors)
|
91
|
+
expect(errors).to eq({ key: 'is not an odd number' })
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with postal code pattern' do
|
96
|
+
it 'validates correct postal codes' do
|
97
|
+
postal_code_validator.validate(:key, '12345', {}, errors)
|
98
|
+
expect(errors).to be_empty
|
99
|
+
|
100
|
+
errors.clear
|
101
|
+
postal_code_validator.validate(:key, '12345-6789', {}, errors)
|
102
|
+
expect(errors).to be_empty
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'rejects invalid postal codes' do
|
106
|
+
postal_code_validator.validate(:key, '1234', {}, errors)
|
107
|
+
expect(errors).to eq({ key: 'is not a valid US postal code' })
|
108
|
+
|
109
|
+
errors.clear
|
110
|
+
postal_code_validator.validate(:key, '12345-678', {}, errors)
|
111
|
+
expect(errors).to eq({ key: 'is not a valid US postal code' })
|
112
|
+
|
113
|
+
errors.clear
|
114
|
+
postal_code_validator.validate(:key, 'ABCDE', {}, errors)
|
115
|
+
expect(errors).to eq({ key: 'is not a valid US postal code' })
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'Integration with HashValidator.add_validator' do
|
121
|
+
before do
|
122
|
+
HashValidator.add_validator('phone_number',
|
123
|
+
pattern: /\A\d{3}-\d{3}-\d{4}\z/,
|
124
|
+
error_message: 'is not a valid phone number')
|
125
|
+
end
|
126
|
+
|
127
|
+
after do
|
128
|
+
HashValidator.remove_validator('phone_number')
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'can be registered and used via add_validator' do
|
132
|
+
validator = HashValidator.validate(
|
133
|
+
{ phone: '555-123-4567' },
|
134
|
+
{ phone: 'phone_number' }
|
135
|
+
)
|
136
|
+
expect(validator.valid?).to eq true
|
137
|
+
expect(validator.errors).to be_empty
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'returns errors for invalid values' do
|
141
|
+
validator = HashValidator.validate(
|
142
|
+
{ phone: '5551234567' },
|
143
|
+
{ phone: 'phone_number' }
|
144
|
+
)
|
145
|
+
expect(validator.valid?).to eq false
|
146
|
+
expect(validator.errors).to eq({ phone: 'is not a valid phone number' })
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashValidator::Validator::IpValidator do
|
4
|
+
let(:validator) { HashValidator::Validator::IpValidator.new }
|
5
|
+
|
6
|
+
context 'valid IP addresses' do
|
7
|
+
it 'validates IPv4 addresses' do
|
8
|
+
errors = {}
|
9
|
+
validator.validate('key', '192.168.1.1', {}, errors)
|
10
|
+
expect(errors).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'validates IPv4 localhost' do
|
14
|
+
errors = {}
|
15
|
+
validator.validate('key', '127.0.0.1', {}, errors)
|
16
|
+
expect(errors).to be_empty
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'validates IPv4 zero address' do
|
20
|
+
errors = {}
|
21
|
+
validator.validate('key', '0.0.0.0', {}, errors)
|
22
|
+
expect(errors).to be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'validates IPv4 broadcast address' do
|
26
|
+
errors = {}
|
27
|
+
validator.validate('key', '255.255.255.255', {}, errors)
|
28
|
+
expect(errors).to be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'validates IPv6 addresses' do
|
32
|
+
errors = {}
|
33
|
+
validator.validate('key', '2001:db8:85a3::8a2e:370:7334', {}, errors)
|
34
|
+
expect(errors).to be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'validates IPv6 localhost' do
|
38
|
+
errors = {}
|
39
|
+
validator.validate('key', '::1', {}, errors)
|
40
|
+
expect(errors).to be_empty
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'validates IPv6 zero address' do
|
44
|
+
errors = {}
|
45
|
+
validator.validate('key', '::', {}, errors)
|
46
|
+
expect(errors).to be_empty
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'validates IPv4-mapped IPv6 addresses' do
|
50
|
+
errors = {}
|
51
|
+
validator.validate('key', '::ffff:192.168.1.1', {}, errors)
|
52
|
+
expect(errors).to be_empty
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'invalid IP addresses' do
|
57
|
+
it 'rejects non-string values' do
|
58
|
+
errors = {}
|
59
|
+
validator.validate('key', 123, {}, errors)
|
60
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'rejects nil values' do
|
64
|
+
errors = {}
|
65
|
+
validator.validate('key', nil, {}, errors)
|
66
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'rejects malformed IPv4 addresses' do
|
70
|
+
errors = {}
|
71
|
+
validator.validate('key', '256.1.1.1', {}, errors)
|
72
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'rejects malformed IPv6 addresses' do
|
76
|
+
errors = {}
|
77
|
+
validator.validate('key', '2001:db8:85a3::8a2e::7334', {}, errors)
|
78
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'rejects non-IP strings' do
|
82
|
+
errors = {}
|
83
|
+
validator.validate('key', 'not an ip', {}, errors)
|
84
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'rejects empty strings' do
|
88
|
+
errors = {}
|
89
|
+
validator.validate('key', '', {}, errors)
|
90
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'rejects hostnames' do
|
94
|
+
errors = {}
|
95
|
+
validator.validate('key', 'example.com', {}, errors)
|
96
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'rejects URLs' do
|
100
|
+
errors = {}
|
101
|
+
validator.validate('key', 'http://192.168.1.1', {}, errors)
|
102
|
+
expect(errors['key']).to eq('is not a valid IP address')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashValidator::Validator::Ipv4Validator do
|
4
|
+
let(:validator) { HashValidator::Validator::Ipv4Validator.new }
|
5
|
+
|
6
|
+
context 'valid IPv4 addresses' do
|
7
|
+
it 'validates standard IPv4 addresses' do
|
8
|
+
errors = {}
|
9
|
+
validator.validate('key', '192.168.1.1', {}, errors)
|
10
|
+
expect(errors).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'validates localhost' do
|
14
|
+
errors = {}
|
15
|
+
validator.validate('key', '127.0.0.1', {}, errors)
|
16
|
+
expect(errors).to be_empty
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'validates zero address' do
|
20
|
+
errors = {}
|
21
|
+
validator.validate('key', '0.0.0.0', {}, errors)
|
22
|
+
expect(errors).to be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'validates broadcast address' do
|
26
|
+
errors = {}
|
27
|
+
validator.validate('key', '255.255.255.255', {}, errors)
|
28
|
+
expect(errors).to be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'validates private network addresses' do
|
32
|
+
errors = {}
|
33
|
+
validator.validate('key', '10.0.0.1', {}, errors)
|
34
|
+
expect(errors).to be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'validates Class B private addresses' do
|
38
|
+
errors = {}
|
39
|
+
validator.validate('key', '172.16.0.1', {}, errors)
|
40
|
+
expect(errors).to be_empty
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'invalid IPv4 addresses' do
|
45
|
+
it 'rejects non-string values' do
|
46
|
+
errors = {}
|
47
|
+
validator.validate('key', 123, {}, errors)
|
48
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'rejects nil values' do
|
52
|
+
errors = {}
|
53
|
+
validator.validate('key', nil, {}, errors)
|
54
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'rejects octets over 255' do
|
58
|
+
errors = {}
|
59
|
+
validator.validate('key', '256.1.1.1', {}, errors)
|
60
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'rejects too few octets' do
|
64
|
+
errors = {}
|
65
|
+
validator.validate('key', '192.168.1', {}, errors)
|
66
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'rejects too many octets' do
|
70
|
+
errors = {}
|
71
|
+
validator.validate('key', '192.168.1.1.1', {}, errors)
|
72
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'rejects IPv6 addresses' do
|
76
|
+
errors = {}
|
77
|
+
validator.validate('key', '2001:db8::1', {}, errors)
|
78
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'rejects malformed addresses' do
|
82
|
+
errors = {}
|
83
|
+
validator.validate('key', '192.168.1.', {}, errors)
|
84
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'rejects empty strings' do
|
88
|
+
errors = {}
|
89
|
+
validator.validate('key', '', {}, errors)
|
90
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'rejects non-numeric octets' do
|
94
|
+
errors = {}
|
95
|
+
validator.validate('key', '192.168.a.1', {}, errors)
|
96
|
+
expect(errors['key']).to eq('is not a valid IPv4 address')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashValidator::Validator::Ipv6Validator do
|
4
|
+
let(:validator) { HashValidator::Validator::Ipv6Validator.new }
|
5
|
+
|
6
|
+
context 'valid IPv6 addresses' do
|
7
|
+
it 'validates full IPv6 addresses' do
|
8
|
+
errors = {}
|
9
|
+
validator.validate('key', '2001:0db8:85a3:0000:0000:8a2e:0370:7334', {}, errors)
|
10
|
+
expect(errors).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'validates compressed IPv6 addresses' do
|
14
|
+
errors = {}
|
15
|
+
validator.validate('key', '2001:db8:85a3::8a2e:370:7334', {}, errors)
|
16
|
+
expect(errors).to be_empty
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'validates IPv6 localhost' do
|
20
|
+
errors = {}
|
21
|
+
validator.validate('key', '::1', {}, errors)
|
22
|
+
expect(errors).to be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'validates IPv6 zero address' do
|
26
|
+
errors = {}
|
27
|
+
validator.validate('key', '::', {}, errors)
|
28
|
+
expect(errors).to be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'validates IPv6 with leading zeros' do
|
32
|
+
errors = {}
|
33
|
+
validator.validate('key', '2001:0db8::0001', {}, errors)
|
34
|
+
expect(errors).to be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'validates IPv6 with mixed case' do
|
38
|
+
errors = {}
|
39
|
+
validator.validate('key', '2001:DB8::1', {}, errors)
|
40
|
+
expect(errors).to be_empty
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'validates IPv4-mapped IPv6 addresses' do
|
44
|
+
errors = {}
|
45
|
+
validator.validate('key', '::ffff:192.168.1.1', {}, errors)
|
46
|
+
expect(errors).to be_empty
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'invalid IPv6 addresses' do
|
51
|
+
it 'rejects non-string values' do
|
52
|
+
errors = {}
|
53
|
+
validator.validate('key', 123, {}, errors)
|
54
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'rejects nil values' do
|
58
|
+
errors = {}
|
59
|
+
validator.validate('key', nil, {}, errors)
|
60
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'rejects IPv4 addresses' do
|
64
|
+
errors = {}
|
65
|
+
validator.validate('key', '192.168.1.1', {}, errors)
|
66
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'rejects malformed IPv6 addresses' do
|
70
|
+
errors = {}
|
71
|
+
validator.validate('key', '2001:db8:85a3::8a2e::7334', {}, errors)
|
72
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'rejects too many groups' do
|
76
|
+
errors = {}
|
77
|
+
validator.validate('key', '2001:0db8:85a3:0000:0000:8a2e:0370:7334:extra', {}, errors)
|
78
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'rejects invalid characters' do
|
82
|
+
errors = {}
|
83
|
+
validator.validate('key', '2001:db8:85a3::8a2g:370:7334', {}, errors)
|
84
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'rejects empty strings' do
|
88
|
+
errors = {}
|
89
|
+
validator.validate('key', '', {}, errors)
|
90
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'rejects incomplete addresses' do
|
94
|
+
errors = {}
|
95
|
+
validator.validate('key', '2001:db8:', {}, errors)
|
96
|
+
expect(errors['key']).to eq('is not a valid IPv6 address')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|