input_sanitizer 0.1.10 → 0.4.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.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yaml +26 -0
- data/.github/workflows/gempush.yml +28 -0
- data/.gitignore +2 -1
- data/CHANGELOG +99 -0
- data/LICENSE +201 -22
- data/README.md +24 -4
- data/input_sanitizer.gemspec +10 -4
- data/lib/input_sanitizer.rb +5 -2
- data/lib/input_sanitizer/errors.rb +142 -0
- data/lib/input_sanitizer/extended_converters.rb +5 -42
- data/lib/input_sanitizer/extended_converters/comma_joined_integers_converter.rb +15 -0
- data/lib/input_sanitizer/extended_converters/comma_joined_strings_converter.rb +15 -0
- data/lib/input_sanitizer/extended_converters/positive_integer_converter.rb +12 -0
- data/lib/input_sanitizer/extended_converters/specific_values_converter.rb +19 -0
- data/lib/input_sanitizer/restricted_hash.rb +49 -8
- data/lib/input_sanitizer/v1.rb +22 -0
- data/lib/input_sanitizer/v1/clean_field.rb +38 -0
- data/lib/input_sanitizer/{default_converters.rb → v1/default_converters.rb} +20 -13
- data/lib/input_sanitizer/v1/sanitizer.rb +166 -0
- data/lib/input_sanitizer/v2.rb +13 -0
- data/lib/input_sanitizer/v2/clean_field.rb +36 -0
- data/lib/input_sanitizer/v2/clean_payload_collection_field.rb +41 -0
- data/lib/input_sanitizer/v2/clean_query_collection_field.rb +40 -0
- data/lib/input_sanitizer/v2/error_collection.rb +49 -0
- data/lib/input_sanitizer/v2/nested_sanitizer_factory.rb +19 -0
- data/lib/input_sanitizer/v2/payload_sanitizer.rb +130 -0
- data/lib/input_sanitizer/v2/payload_transform.rb +42 -0
- data/lib/input_sanitizer/v2/query_sanitizer.rb +33 -0
- data/lib/input_sanitizer/v2/types.rb +227 -0
- data/lib/input_sanitizer/version.rb +1 -1
- data/spec/extended_converters/comma_joined_integers_converter_spec.rb +18 -0
- data/spec/extended_converters/comma_joined_strings_converter_spec.rb +18 -0
- data/spec/extended_converters/positive_integer_converter_spec.rb +18 -0
- data/spec/extended_converters/specific_values_converter_spec.rb +27 -0
- data/spec/restricted_hash_spec.rb +37 -7
- data/spec/sanitizer_spec.rb +129 -26
- data/spec/spec_helper.rb +17 -2
- data/spec/v1/default_converters_spec.rb +141 -0
- data/spec/v2/converters_spec.rb +174 -0
- data/spec/v2/payload_sanitizer_spec.rb +534 -0
- data/spec/v2/payload_transform_spec.rb +98 -0
- data/spec/v2/query_sanitizer_spec.rb +300 -0
- data/v2.md +52 -0
- metadata +105 -40
- data/.travis.yml +0 -12
- data/lib/input_sanitizer/sanitizer.rb +0 -140
- data/spec/default_converters_spec.rb +0 -101
- data/spec/extended_converters_spec.rb +0 -62
@@ -0,0 +1,534 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class AddressSanitizer < InputSanitizer::V2::PayloadSanitizer
|
4
|
+
string :city
|
5
|
+
string :zip
|
6
|
+
end
|
7
|
+
|
8
|
+
class TagSanitizer < InputSanitizer::V2::PayloadSanitizer
|
9
|
+
integer :id
|
10
|
+
string :name
|
11
|
+
nested :addresses, :sanitizer => AddressSanitizer, :collection => true
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestedPayloadSanitizer < InputSanitizer::V2::PayloadSanitizer
|
15
|
+
integer :array, :collection => true
|
16
|
+
integer :array_nil, :collection => true, :allow_nil => true
|
17
|
+
string :status, :allow => ['current', 'past']
|
18
|
+
string :status_with_empty, :allow => ['', 'current', 'past']
|
19
|
+
string :regexp_string, :regexp => /^#?([a-f0-9]{6}|[a-f0-9]{3})$/
|
20
|
+
string :utf8mb4_string, :strip_4byte_chars => true
|
21
|
+
string :value_restricted_utf8mb4_string, :strip_4byte_chars => true, :allow => ['test']
|
22
|
+
string :non_blank_utf8mb4_string, :strip_4byte_chars => true, :allow_blank => false
|
23
|
+
string :size_restricted_utf8mb4_string, :strip_4byte_chars => true, :minimum => 2, :maximum => 4
|
24
|
+
nested :address, :sanitizer => AddressSanitizer
|
25
|
+
nested :nullable_address, :sanitizer => AddressSanitizer, :allow_nil => true
|
26
|
+
nested :tags, :sanitizer => TagSanitizer, :collection => true
|
27
|
+
|
28
|
+
float :float_attribute, :minimum => 1, :maximum => 100
|
29
|
+
integer :integer_attribute, :minimum => 1, :maximum => 100
|
30
|
+
string :string_attribute
|
31
|
+
boolean :bool_attribute
|
32
|
+
datetime :datetime_attribute
|
33
|
+
date :date_attribute, :minimum => Date.new(-2015, 01, 01), :maximum => Date.new(2015, 12, 31)
|
34
|
+
|
35
|
+
url :website
|
36
|
+
string :limited_collection, :collection => { :minimum => 1, :maximum => 2 }, :minimum => 2, :maximum => 12
|
37
|
+
string :allow_collection, :collection => true, :allow => ['yes', 'no']
|
38
|
+
end
|
39
|
+
|
40
|
+
class BlankValuesPayloadSanitizer < InputSanitizer::V2::PayloadSanitizer
|
41
|
+
string :required_string, :required => true
|
42
|
+
datetime :non_nil_datetime, :allow_nil => false
|
43
|
+
url :non_blank_url, :allow_blank => false
|
44
|
+
end
|
45
|
+
|
46
|
+
class CustomConverterWithProvidedValue < InputSanitizer::V2::PayloadSanitizer
|
47
|
+
integer :from
|
48
|
+
custom :to, :provide => :from, :converter => lambda { |value, options|
|
49
|
+
InputSanitizer::V2::Types::IntegerCheck.new.call(value)
|
50
|
+
raise InputSanitizer::ValueError.new(value, options[:provided][:from], nil) if options[:provided][:from] > value
|
51
|
+
value
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
describe InputSanitizer::V2::PayloadSanitizer do
|
56
|
+
let(:sanitizer) { TestedPayloadSanitizer.new(@params) }
|
57
|
+
let(:cleaned) { sanitizer.cleaned }
|
58
|
+
|
59
|
+
describe "collections" do
|
60
|
+
it "is invalid if collection is not an array" do
|
61
|
+
@params = { :array => {} }
|
62
|
+
sanitizer.should_not be_valid
|
63
|
+
end
|
64
|
+
|
65
|
+
it "is valid if collection is an array" do
|
66
|
+
@params = { :array => [] }
|
67
|
+
sanitizer.should be_valid
|
68
|
+
end
|
69
|
+
|
70
|
+
it "is valid if collection is an nil and allow_nil is passed" do
|
71
|
+
@params = { :array_nil => nil }
|
72
|
+
sanitizer.should be_valid
|
73
|
+
end
|
74
|
+
|
75
|
+
it "is invalid if there are too few elements" do
|
76
|
+
@params = { :limited_collection => [] }
|
77
|
+
sanitizer.should_not be_valid
|
78
|
+
end
|
79
|
+
|
80
|
+
it "is invalid if there are too many elements" do
|
81
|
+
@params = { :limited_collection => ['bear', 'bear', 'bear'] }
|
82
|
+
sanitizer.should_not be_valid
|
83
|
+
end
|
84
|
+
|
85
|
+
it "is valid when there are just enough elements" do
|
86
|
+
@params = { :limited_collection => ['goldilocks'] }
|
87
|
+
sanitizer.should be_valid
|
88
|
+
end
|
89
|
+
|
90
|
+
it "is invalid when any of the elements are too long" do
|
91
|
+
@params = { :limited_collection => ['more_than_the_limit'] }
|
92
|
+
sanitizer.should_not be_valid
|
93
|
+
end
|
94
|
+
|
95
|
+
it "is invalid when any of the elements are too short" do
|
96
|
+
@params = { :limited_collection => ['a'] }
|
97
|
+
sanitizer.should_not be_valid
|
98
|
+
end
|
99
|
+
|
100
|
+
it "is invalid when given disallowed value in a collection" do
|
101
|
+
@params = { :allow_collection => ['yes', 'no', 'whoa'] }
|
102
|
+
sanitizer.should_not be_valid
|
103
|
+
end
|
104
|
+
|
105
|
+
it "is valid when given allowed values in a collection" do
|
106
|
+
@params = { :allow_collection => ['yes', 'no'] }
|
107
|
+
sanitizer.should be_valid
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "allow option" do
|
112
|
+
it "is valid when given an allowed string" do
|
113
|
+
@params = { :status => 'past' }
|
114
|
+
sanitizer.should be_valid
|
115
|
+
end
|
116
|
+
|
117
|
+
it "is invalid when given an empty string" do
|
118
|
+
@params = { :status => '' }
|
119
|
+
sanitizer.should_not be_valid
|
120
|
+
sanitizer.errors[0].field.should eq('/status')
|
121
|
+
end
|
122
|
+
|
123
|
+
it "is valid when given an allowed empty string" do
|
124
|
+
@params = { :status_with_empty => '' }
|
125
|
+
sanitizer.should be_valid
|
126
|
+
end
|
127
|
+
|
128
|
+
it "is invalid when given a disallowed string" do
|
129
|
+
@params = { :status => 'current bad string' }
|
130
|
+
sanitizer.should_not be_valid
|
131
|
+
sanitizer.errors[0].field.should eq('/status')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "minimum and maximum options" do
|
136
|
+
it "is invalid if integer is lower than the minimum" do
|
137
|
+
@params = { :integer_attribute => 0 }
|
138
|
+
sanitizer.should_not be_valid
|
139
|
+
end
|
140
|
+
|
141
|
+
it "is invalid if integer is greater than the maximum" do
|
142
|
+
@params = { :integer_attribute => 101 }
|
143
|
+
sanitizer.should_not be_valid
|
144
|
+
end
|
145
|
+
|
146
|
+
it "is valid when integer is within given range" do
|
147
|
+
@params = { :limited_collection => ['goldilocks'] }
|
148
|
+
sanitizer.should be_valid
|
149
|
+
end
|
150
|
+
|
151
|
+
it "is invalid if float is lower than the minimum" do
|
152
|
+
@params = { :float_attribute => 0.0 }
|
153
|
+
sanitizer.should_not be_valid
|
154
|
+
end
|
155
|
+
|
156
|
+
it "is invalid if float is greater than the maximum" do
|
157
|
+
@params = { :float_attribute => 101.0 }
|
158
|
+
sanitizer.should_not be_valid
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "strip_4byte_chars option" do
|
163
|
+
it "is valid when given a string with 4-byte chars" do
|
164
|
+
@params = { :utf8mb4_string => "test \u{1F435} value" }
|
165
|
+
sanitizer.should be_valid
|
166
|
+
end
|
167
|
+
|
168
|
+
it "returns sanitized string without 4-byte chars" do
|
169
|
+
@params = { :utf8mb4_string => "test\u{1F435}" }
|
170
|
+
sanitizer[:utf8mb4_string].should eq "test"
|
171
|
+
end
|
172
|
+
|
173
|
+
it "properly handles string with 4-byte char at the beginning" do
|
174
|
+
@params = { :utf8mb4_string => "\u{1F435} 4-byte char at the beginning" }
|
175
|
+
sanitizer[:utf8mb4_string].should eq ' 4-byte char at the beginning'
|
176
|
+
end
|
177
|
+
|
178
|
+
it "properly handles string with 4-byte char in the middle" do
|
179
|
+
@params = { :utf8mb4_string => "4-byte char\u{1F435} in the middle" }
|
180
|
+
sanitizer[:utf8mb4_string].should eq '4-byte char in the middle'
|
181
|
+
end
|
182
|
+
|
183
|
+
it "properly handles string with 4-byte char at the end" do
|
184
|
+
@params = { :utf8mb4_string => "4-byte char at the end \u{1F435}" }
|
185
|
+
sanitizer[:utf8mb4_string].should eq '4-byte char at the end '
|
186
|
+
end
|
187
|
+
|
188
|
+
it "does not strip 3-byte chars" do
|
189
|
+
@params = { :utf8mb4_string => "Test \u{270A}" }
|
190
|
+
sanitizer[:utf8mb4_string].should eq "Test \u{270A}"
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "when used with other options" do
|
194
|
+
describe "allow" do
|
195
|
+
it "is valid when string matches any value in allowlist before stripping 4-byte chars" do
|
196
|
+
@params = { :value_restricted_utf8mb4_string => "test" }
|
197
|
+
sanitizer.should be_valid
|
198
|
+
end
|
199
|
+
|
200
|
+
it "is invalid when string doesn't match any value in allowlist before stripping 4-byte chars" do
|
201
|
+
@params = { :value_restricted_utf8mb4_string => "test\u{1F435}" }
|
202
|
+
sanitizer.should_not be_valid
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "allow_blank=false" do
|
207
|
+
it "is invalid when string is already blank before stripping 4-byte chars" do
|
208
|
+
@params = { :non_blank_utf8mb4_string => " " }
|
209
|
+
sanitizer.should_not be_valid
|
210
|
+
end
|
211
|
+
|
212
|
+
it "is invalid when string becomes blank as a result of stripping 4-byte chars" do
|
213
|
+
@params = { :non_blank_utf8mb4_string => " \u{1F435} " }
|
214
|
+
sanitizer.should_not be_valid
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "minimum and maximum" do
|
219
|
+
it "is invalid when string is already too long before stripping 4-byte chars" do
|
220
|
+
@params = { :size_restricted_utf8mb4_string => "1234\u{1F435}" }
|
221
|
+
sanitizer.should_not be_valid
|
222
|
+
end
|
223
|
+
|
224
|
+
it "is invalid when string becomes too short as a result of stripping 4-byte chars" do
|
225
|
+
@params = { :size_restricted_utf8mb4_string => "1\u{1F435}" }
|
226
|
+
sanitizer.should_not be_valid
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "strict param checking" do
|
233
|
+
it "is invalid when given extra params" do
|
234
|
+
@params = { :extra => 'test', :extra2 => 1 }
|
235
|
+
sanitizer.should_not be_valid
|
236
|
+
sanitizer.errors.count.should eq(2)
|
237
|
+
end
|
238
|
+
|
239
|
+
it "is invalid when given extra params in a nested sanitizer" do
|
240
|
+
@params = { :address => { :extra => 0 }, :tags => [ { :extra2 => 1 } ] }
|
241
|
+
sanitizer.should_not be_valid
|
242
|
+
sanitizer.errors.map(&:field).should contain_exactly('/address/extra', '/tags/0/extra2')
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe "converters with provided values" do
|
247
|
+
let(:sanitizer) { CustomConverterWithProvidedValue.new(@params) }
|
248
|
+
|
249
|
+
it "is valid when converter passes check with provided value" do
|
250
|
+
@params = {from: 1, to: 3}
|
251
|
+
sanitizer.should be_valid
|
252
|
+
end
|
253
|
+
|
254
|
+
it "is invalid when converter does not pass check with provided value" do
|
255
|
+
@params = {from: 3, to: 1}
|
256
|
+
sanitizer.should_not be_valid
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe "strict type checking" do
|
261
|
+
it "is invalid when given string instead of integer" do
|
262
|
+
@params = { :integer_attribute => '1' }
|
263
|
+
sanitizer.should_not be_valid
|
264
|
+
sanitizer.errors[0].field.should eq('/integer_attribute')
|
265
|
+
end
|
266
|
+
|
267
|
+
it "is valid when given an integer" do
|
268
|
+
@params = { :integer_attribute => 50 }
|
269
|
+
sanitizer.should be_valid
|
270
|
+
sanitizer[:integer_attribute].should eq(50)
|
271
|
+
end
|
272
|
+
|
273
|
+
it "is invalid when given a float" do
|
274
|
+
@params = { :integer_attribute => 50.99 }
|
275
|
+
sanitizer.should_not be_valid
|
276
|
+
end
|
277
|
+
|
278
|
+
it "is valid when given nil for an integer" do
|
279
|
+
@params = { :integer_attribute => nil }
|
280
|
+
sanitizer.should be_valid
|
281
|
+
sanitizer[:integer_attribute].should be_nil
|
282
|
+
end
|
283
|
+
|
284
|
+
it "is invalid when given string instead of float" do
|
285
|
+
@params = { :float_attribute => '1' }
|
286
|
+
sanitizer.should_not be_valid
|
287
|
+
sanitizer.errors[0].field.should eq('/float_attribute')
|
288
|
+
end
|
289
|
+
|
290
|
+
it "is valid when given a float" do
|
291
|
+
@params = { :float_attribute => 50.0 }
|
292
|
+
sanitizer.should be_valid
|
293
|
+
sanitizer[:float_attribute].should eq(50.0)
|
294
|
+
end
|
295
|
+
|
296
|
+
it "is valid when given nil for a float" do
|
297
|
+
@params = { :float_attribute => nil }
|
298
|
+
sanitizer.should be_valid
|
299
|
+
sanitizer[:float_attribute].should be_nil
|
300
|
+
end
|
301
|
+
|
302
|
+
it "is valid when given string is matching regexp" do
|
303
|
+
@params = { :regexp_string => "#8bd635" }
|
304
|
+
sanitizer.should be_valid
|
305
|
+
sanitizer[:regexp_string].should eq('#8bd635')
|
306
|
+
end
|
307
|
+
|
308
|
+
it "is invalid when given string is not matching regexp" do
|
309
|
+
@params = { :regexp_string => "not a hex value" }
|
310
|
+
sanitizer.should_not be_valid
|
311
|
+
sanitizer.errors[0].field.should eq('/regexp_string')
|
312
|
+
end
|
313
|
+
|
314
|
+
it "is invalid when given integer instead of string" do
|
315
|
+
@params = { :string_attribute => 0 }
|
316
|
+
sanitizer.should_not be_valid
|
317
|
+
sanitizer.errors[0].field.should eq('/string_attribute')
|
318
|
+
end
|
319
|
+
|
320
|
+
it "is invalid when given float instead of string" do
|
321
|
+
@params = { :string_attribute => 3.1415 }
|
322
|
+
sanitizer.should_not be_valid
|
323
|
+
sanitizer.errors[0].field.should eq('/string_attribute')
|
324
|
+
end
|
325
|
+
|
326
|
+
it "is valid when given a string" do
|
327
|
+
@params = { :string_attribute => '#@!#%#$@#ad' }
|
328
|
+
sanitizer.should be_valid
|
329
|
+
sanitizer[:string_attribute].should eq('#@!#%#$@#ad')
|
330
|
+
end
|
331
|
+
|
332
|
+
it "is invalid when given 'yes' as a bool" do
|
333
|
+
@params = { :bool_attribute => 'yes' }
|
334
|
+
sanitizer.should_not be_valid
|
335
|
+
sanitizer.errors[0].field.should eq('/bool_attribute')
|
336
|
+
end
|
337
|
+
|
338
|
+
it "is valid when given true as a bool" do
|
339
|
+
@params = { :bool_attribute => true }
|
340
|
+
sanitizer.should be_valid
|
341
|
+
end
|
342
|
+
|
343
|
+
it "is valid when given false as a bool" do
|
344
|
+
@params = { :bool_attribute => false }
|
345
|
+
sanitizer.should be_valid
|
346
|
+
end
|
347
|
+
|
348
|
+
it "is invalid when given an incorrect datetime" do
|
349
|
+
@params = { :datetime_attribute => "2014-08-2716:32:56Z" }
|
350
|
+
sanitizer.should_not be_valid
|
351
|
+
sanitizer.errors[0].field.should eq('/datetime_attribute')
|
352
|
+
end
|
353
|
+
|
354
|
+
it "is valid when given a correct datetime" do
|
355
|
+
@params = { :datetime_attribute => "2014-08-27T16:32:56Z" }
|
356
|
+
sanitizer.should be_valid
|
357
|
+
end
|
358
|
+
|
359
|
+
it "is valid when given a 'forever' timestamp" do
|
360
|
+
@params = { :datetime_attribute => "9999-12-31T00:00:00Z" }
|
361
|
+
sanitizer.should be_valid
|
362
|
+
end
|
363
|
+
|
364
|
+
it "is invalid when given an incorrect date" do
|
365
|
+
@params = { :date_attribute => "invalid" }
|
366
|
+
sanitizer.should_not be_valid
|
367
|
+
sanitizer.errors[0].field.should eq('/date_attribute')
|
368
|
+
end
|
369
|
+
|
370
|
+
it "is valid when given a correct date" do
|
371
|
+
@params = { :date_attribute => "2015-08-27" }
|
372
|
+
sanitizer.should be_valid
|
373
|
+
end
|
374
|
+
|
375
|
+
it "is valid when given a correct negative date" do
|
376
|
+
@params = { :date_attribute => "-2014-08-27" }
|
377
|
+
sanitizer.should be_valid
|
378
|
+
end
|
379
|
+
|
380
|
+
it "is valid when given a correct URL" do
|
381
|
+
@params = { :website => "https://google.com" }
|
382
|
+
sanitizer.should be_valid
|
383
|
+
sanitizer[:website].should eq("https://google.com")
|
384
|
+
end
|
385
|
+
|
386
|
+
it "is invalid when given an invalid URL" do
|
387
|
+
@params = { :website => "ht:/google.com" }
|
388
|
+
sanitizer.should_not be_valid
|
389
|
+
end
|
390
|
+
|
391
|
+
it "is invalid when given an invalid URL that contains a valid URL" do
|
392
|
+
@params = { :website => "watwat http://google.com wat" }
|
393
|
+
sanitizer.should_not be_valid
|
394
|
+
end
|
395
|
+
|
396
|
+
describe "blank and required values" do
|
397
|
+
let(:sanitizer) { BlankValuesPayloadSanitizer.new(@params) }
|
398
|
+
let(:defaults) { { :required_string => 'zz' } }
|
399
|
+
|
400
|
+
it "is invalid if required string is missing" do
|
401
|
+
@params = {}
|
402
|
+
sanitizer.should_not be_valid
|
403
|
+
sanitizer.errors[0].should be_an_instance_of(InputSanitizer::ValueMissingError)
|
404
|
+
sanitizer.errors[0].field.should eq('/required_string')
|
405
|
+
end
|
406
|
+
|
407
|
+
it "is invalid if required string is nil" do
|
408
|
+
@params = { :required_string => nil }
|
409
|
+
sanitizer.should_not be_valid
|
410
|
+
sanitizer.errors[0].should be_an_instance_of(InputSanitizer::BlankValueError)
|
411
|
+
sanitizer.errors[0].field.should eq('/required_string')
|
412
|
+
end
|
413
|
+
|
414
|
+
it "is invalid if required string is blank" do
|
415
|
+
@params = { :required_string => ' ' }
|
416
|
+
sanitizer.should_not be_valid
|
417
|
+
sanitizer.errors[0].should be_an_instance_of(InputSanitizer::BlankValueError)
|
418
|
+
sanitizer.errors[0].field.should eq('/required_string')
|
419
|
+
end
|
420
|
+
|
421
|
+
it "is invalid if non-nil datetime is null" do
|
422
|
+
@params = defaults.merge({ :non_nil_datetime => nil })
|
423
|
+
sanitizer.should_not be_valid
|
424
|
+
sanitizer.errors[0].should be_an_instance_of(InputSanitizer::BlankValueError)
|
425
|
+
sanitizer.errors[0].field.should eq('/non_nil_datetime')
|
426
|
+
end
|
427
|
+
|
428
|
+
it "is valid if non-nil datetime is blank" do
|
429
|
+
@params = defaults.merge({ :non_nil_datetime => '' })
|
430
|
+
sanitizer.should be_valid
|
431
|
+
end
|
432
|
+
|
433
|
+
it "is invalid if non-blank url is nil" do
|
434
|
+
@params = defaults.merge({ :non_blank_url => nil })
|
435
|
+
sanitizer.should_not be_valid
|
436
|
+
sanitizer.errors[0].should be_an_instance_of(InputSanitizer::BlankValueError)
|
437
|
+
sanitizer.errors[0].field.should eq('/non_blank_url')
|
438
|
+
end
|
439
|
+
|
440
|
+
it "is invalid if non-blank url is blank" do
|
441
|
+
@params = defaults.merge({ :non_blank_url => '' })
|
442
|
+
sanitizer.should_not be_valid
|
443
|
+
sanitizer.errors[0].should be_an_instance_of(InputSanitizer::BlankValueError)
|
444
|
+
sanitizer.errors[0].field.should eq('/non_blank_url')
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
describe "nested checking" do
|
449
|
+
describe "simple array" do
|
450
|
+
it "returns JSON pointer for invalid fields" do
|
451
|
+
@params = { :array => [1, 'z', '3', 4] }
|
452
|
+
sanitizer.errors.length.should eq(2)
|
453
|
+
sanitizer.errors.map(&:field).should contain_exactly('/array/1', '/array/2')
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
describe "nested object" do
|
458
|
+
it "returns an error when given a nil for a nested value" do
|
459
|
+
@params = { :address => nil }
|
460
|
+
sanitizer.should_not be_valid
|
461
|
+
end
|
462
|
+
|
463
|
+
it "returns an error when given a string for a nested value" do
|
464
|
+
@params = { :address => 'nope' }
|
465
|
+
sanitizer.should_not be_valid
|
466
|
+
end
|
467
|
+
|
468
|
+
it "returns an error when given an array for a nested value" do
|
469
|
+
@params = { :address => ['a'] }
|
470
|
+
sanitizer.should_not be_valid
|
471
|
+
end
|
472
|
+
|
473
|
+
it "returns JSON pointer for invalid fields" do
|
474
|
+
@params = { :address => { :city => 0, :zip => 1 } }
|
475
|
+
sanitizer.errors.length.should eq(2)
|
476
|
+
sanitizer.errors.map(&:field).should contain_exactly('/address/city', '/address/zip')
|
477
|
+
end
|
478
|
+
|
479
|
+
it "allows nil with `allow_nil` flag" do
|
480
|
+
@params = { :nullable_address => nil }
|
481
|
+
sanitizer.should be_valid
|
482
|
+
sanitizer.cleaned.fetch(:nullable_address).should eq(nil)
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe "array of nested objects" do
|
487
|
+
it "returns an error when given a nil for a collection" do
|
488
|
+
@params = { :tags => nil }
|
489
|
+
sanitizer.should_not be_valid
|
490
|
+
end
|
491
|
+
|
492
|
+
it "returns an error when given a string for a collection" do
|
493
|
+
@params = { :tags => 'nope' }
|
494
|
+
sanitizer.should_not be_valid
|
495
|
+
end
|
496
|
+
|
497
|
+
it "returns an error when given a hash for a collection" do
|
498
|
+
@params = { :tags => { :a => 1 } }
|
499
|
+
sanitizer.should_not be_valid
|
500
|
+
end
|
501
|
+
|
502
|
+
it "returns JSON pointer for invalid fields" do
|
503
|
+
@params = { :tags => [ { :id => 'n', :name => 1 }, { :id => 10, :name => 2 } ] }
|
504
|
+
sanitizer.errors.length.should eq(3)
|
505
|
+
sanitizer.errors.map(&:field).should contain_exactly(
|
506
|
+
'/tags/0/id',
|
507
|
+
'/tags/0/name',
|
508
|
+
'/tags/1/name'
|
509
|
+
)
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
describe "array of nested objects that have array of nested objects" do
|
514
|
+
it "returns JSON pointer for invalid fields" do
|
515
|
+
@params = { :tags => [
|
516
|
+
{ :id => 'n', :addresses => [ { :city => 0 }, { :city => 1 } ] },
|
517
|
+
{ :name => 2, :addresses => [ { :city => 3 } ] },
|
518
|
+
] }
|
519
|
+
sanitizer.errors.length.should eq(5)
|
520
|
+
sanitizer.errors.map(&:field).should contain_exactly(
|
521
|
+
'/tags/0/id',
|
522
|
+
'/tags/0/addresses/0/city',
|
523
|
+
'/tags/0/addresses/1/city',
|
524
|
+
'/tags/1/name',
|
525
|
+
'/tags/1/addresses/0/city'
|
526
|
+
)
|
527
|
+
|
528
|
+
ec = sanitizer.error_collection
|
529
|
+
ec.length.should eq(5)
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|