committee 5.6.1 → 5.6.3

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/committee/drivers/open_api_3/driver.rb +7 -1
  3. data/lib/committee/drivers.rb +2 -3
  4. data/lib/committee/errors.rb +11 -0
  5. data/lib/committee/middleware/base.rb +11 -5
  6. data/lib/committee/middleware/options/base.rb +107 -0
  7. data/lib/committee/middleware/options/request_validation.rb +80 -0
  8. data/lib/committee/middleware/options/response_validation.rb +46 -0
  9. data/lib/committee/middleware/options.rb +12 -0
  10. data/lib/committee/middleware/request_validation.rb +7 -1
  11. data/lib/committee/middleware/response_validation.rb +6 -2
  12. data/lib/committee/middleware.rb +1 -0
  13. data/lib/committee/schema_validator/hyper_schema/response_generator.rb +1 -3
  14. data/lib/committee/schema_validator/hyper_schema/response_validator.rb +14 -1
  15. data/lib/committee/schema_validator/hyper_schema/router.rb +1 -1
  16. data/lib/committee/schema_validator/hyper_schema.rb +3 -14
  17. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +43 -13
  18. data/lib/committee/schema_validator/open_api_3/parameter_deserializer.rb +556 -0
  19. data/lib/committee/schema_validator/open_api_3/response_validator.rb +16 -2
  20. data/lib/committee/schema_validator/open_api_3.rb +19 -13
  21. data/lib/committee/schema_validator/option.rb +6 -17
  22. data/lib/committee/schema_validator.rb +12 -1
  23. data/lib/committee/test/except_parameter.rb +416 -0
  24. data/lib/committee/test/methods.rb +38 -2
  25. data/lib/committee/version.rb +1 -1
  26. data/lib/committee.rb +1 -1
  27. data/test/drivers/open_api_2/driver_test.rb +4 -16
  28. data/test/drivers/open_api_2/parameter_schema_builder_test.rb +4 -50
  29. data/test/drivers_test.rb +35 -21
  30. data/test/middleware/options/base_test.rb +120 -0
  31. data/test/middleware/options/request_validation_test.rb +177 -0
  32. data/test/middleware/options/response_validation_test.rb +121 -0
  33. data/test/middleware/request_validation_open_api_3_test.rb +200 -80
  34. data/test/middleware/request_validation_test.rb +13 -70
  35. data/test/middleware/response_validation_open_api_3_test.rb +40 -17
  36. data/test/middleware/response_validation_test.rb +3 -14
  37. data/test/request_unpacker_test.rb +2 -10
  38. data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +1 -37
  39. data/test/schema_validator/hyper_schema/request_validator_test.rb +6 -30
  40. data/test/schema_validator/hyper_schema/router_test.rb +5 -0
  41. data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +1 -37
  42. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +58 -43
  43. data/test/schema_validator/open_api_3/parameter_deserializer_test.rb +457 -0
  44. data/test/schema_validator/open_api_3/request_validator_test.rb +1 -2
  45. data/test/schema_validator/open_api_3/response_validator_test.rb +3 -11
  46. data/test/schema_validator_test.rb +41 -0
  47. data/test/test/methods_test.rb +238 -105
  48. data/test/test/schema_coverage_test.rb +8 -155
  49. metadata +11 -1
@@ -0,0 +1,457 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe Committee::SchemaValidator::OpenAPI3::ParameterDeserializer do
6
+ before do
7
+ @validator_option = Committee::SchemaValidator::Option.new({}, open_api_3_schema, :open_api_3)
8
+ end
9
+
10
+ describe 'deserialize_parameters option' do
11
+ it 'is enabled by default for OpenAPI 3' do
12
+ option = Committee::SchemaValidator::Option.new({}, open_api_3_schema, :open_api_3)
13
+ assert_equal true, option.deserialize_parameters
14
+ end
15
+
16
+ it 'can be disabled' do
17
+ option = Committee::SchemaValidator::Option.new({ deserialize_parameters: false }, open_api_3_schema, :open_api_3)
18
+ assert_equal false, option.deserialize_parameters
19
+ end
20
+ end
21
+
22
+ describe 'parameter deserialization' do
23
+ it 'deserializes form style object with explode=true' do
24
+ raw_params = { 'role' => 'admin', 'status' => 'active' }
25
+ param = create_param('filter', 'query', 'form', true, 'object', { 'role' => 'string', 'status' => 'string' })
26
+ deserializer = create_deserializer([param])
27
+ result = deserializer.deserialize_query_params(raw_params)
28
+
29
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
30
+ assert_equal 'admin', result[:filter][:role]
31
+ end
32
+
33
+ it 'deserializes form style object with explode=false' do
34
+ raw_params = { 'filter' => 'role,admin,status,active' }
35
+ param = create_param('filter', 'query', 'form', false, 'object', { 'role' => 'string', 'status' => 'string' })
36
+ deserializer = create_deserializer([param])
37
+ result = deserializer.deserialize_query_params(raw_params)
38
+
39
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
40
+ end
41
+
42
+ it 'deserializes form style array with explode=true' do
43
+ raw_params = { 'ids' => ['1', '2', '3'] }
44
+ param = create_param('ids', 'query', 'form', true, 'array', 'integer')
45
+ deserializer = create_deserializer([param])
46
+ result = deserializer.deserialize_query_params(raw_params)
47
+
48
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
49
+ end
50
+
51
+ it 'deserializes form style array with explode=false' do
52
+ raw_params = { 'ids' => '1,2,3' }
53
+ param = create_param('ids', 'query', 'form', false, 'array', 'integer')
54
+ deserializer = create_deserializer([param])
55
+ result = deserializer.deserialize_query_params(raw_params)
56
+
57
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
58
+ end
59
+
60
+ it 'deserializes deepObject style' do
61
+ raw_params = { 'filter[role]' => 'admin', 'filter[status]' => 'active' }
62
+ param = create_param('filter', 'query', 'deepObject', true, 'object', { 'role' => 'string', 'status' => 'string' })
63
+ deserializer = create_deserializer([param])
64
+ result = deserializer.deserialize_query_params(raw_params)
65
+
66
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
67
+ end
68
+
69
+ it 'deserializes spaceDelimited style' do
70
+ raw_params = { 'ids' => '1 2 3' }
71
+ param = create_param('ids', 'query', 'spaceDelimited', false, 'array', 'integer')
72
+ deserializer = create_deserializer([param])
73
+ result = deserializer.deserialize_query_params(raw_params)
74
+
75
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
76
+ end
77
+
78
+ it 'deserializes pipeDelimited style' do
79
+ raw_params = { 'ids' => '1|2|3' }
80
+ param = create_param('ids', 'query', 'pipeDelimited', false, 'array', 'integer')
81
+ deserializer = create_deserializer([param])
82
+ result = deserializer.deserialize_query_params(raw_params)
83
+
84
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
85
+ end
86
+
87
+ it 'deserializes simple style array with explode=false for path params' do
88
+ raw_params = { 'ids' => '1,2,3' }
89
+ param = create_param('ids', 'path', 'simple', false, 'array', 'integer')
90
+ deserializer = create_deserializer([param])
91
+ result = deserializer.deserialize_path_params(raw_params)
92
+
93
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
94
+ end
95
+
96
+ it 'deserializes simple style array with explode=true for path params' do
97
+ raw_params = { 'ids' => ['1', '2', '3'] }
98
+ param = create_param('ids', 'path', 'simple', true, 'array', 'integer')
99
+ deserializer = create_deserializer([param])
100
+ result = deserializer.deserialize_path_params(raw_params)
101
+
102
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
103
+ end
104
+
105
+ it 'deserializes simple style object with explode=false for path params' do
106
+ raw_params = { 'filter' => 'role,admin,status,active' }
107
+ param = create_param('filter', 'path', 'simple', false, 'object', { 'role' => 'string', 'status' => 'string' })
108
+ deserializer = create_deserializer([param])
109
+ result = deserializer.deserialize_path_params(raw_params)
110
+
111
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
112
+ end
113
+
114
+ it 'deserializes simple style object with explode=true for path params' do
115
+ raw_params = { 'filter' => 'role=admin,status=active' }
116
+ param = create_param('filter', 'path', 'simple', true, 'object', { 'role' => 'string', 'status' => 'string' })
117
+ deserializer = create_deserializer([param])
118
+ result = deserializer.deserialize_path_params(raw_params)
119
+
120
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
121
+ end
122
+
123
+ it 'deserializes label style array with explode=false' do
124
+ raw_params = { 'ids' => '.1,2,3' }
125
+ param = create_param('ids', 'path', 'label', false, 'array', 'integer')
126
+ deserializer = create_deserializer([param])
127
+ result = deserializer.deserialize_path_params(raw_params)
128
+
129
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
130
+ end
131
+
132
+ it 'deserializes label style array with explode=true' do
133
+ raw_params = { 'ids' => '.1.2.3' }
134
+ param = create_param('ids', 'path', 'label', true, 'array', 'integer')
135
+ deserializer = create_deserializer([param])
136
+ result = deserializer.deserialize_path_params(raw_params)
137
+
138
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
139
+ end
140
+
141
+ it 'deserializes label style object with explode=false' do
142
+ raw_params = { 'filter' => '.role,admin,status,active' }
143
+ param = create_param('filter', 'path', 'label', false, 'object', { 'role' => 'string', 'status' => 'string' })
144
+ deserializer = create_deserializer([param])
145
+ result = deserializer.deserialize_path_params(raw_params)
146
+
147
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
148
+ end
149
+
150
+ it 'deserializes label style object with explode=true' do
151
+ raw_params = { 'filter' => '.role=admin.status=active' }
152
+ param = create_param('filter', 'path', 'label', true, 'object', { 'role' => 'string', 'status' => 'string' })
153
+ deserializer = create_deserializer([param])
154
+ result = deserializer.deserialize_path_params(raw_params)
155
+
156
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
157
+ end
158
+
159
+ it 'deserializes matrix style array with explode=false' do
160
+ raw_params = { 'ids' => ';ids=1,2,3' }
161
+ param = create_param('ids', 'path', 'matrix', false, 'array', 'integer')
162
+ deserializer = create_deserializer([param])
163
+ result = deserializer.deserialize_path_params(raw_params)
164
+
165
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
166
+ end
167
+
168
+ it 'deserializes matrix style array with explode=true' do
169
+ raw_params = { 'ids' => ['1', '2', '3'] }
170
+ param = create_param('ids', 'path', 'matrix', true, 'array', 'integer')
171
+ deserializer = create_deserializer([param])
172
+ result = deserializer.deserialize_path_params(raw_params)
173
+
174
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
175
+ end
176
+
177
+ it 'deserializes matrix style object with explode=false' do
178
+ raw_params = { 'filter' => ';filter=role,admin,status,active' }
179
+ param = create_param('filter', 'path', 'matrix', false, 'object', { 'role' => 'string', 'status' => 'string' })
180
+ deserializer = create_deserializer([param])
181
+ result = deserializer.deserialize_path_params(raw_params)
182
+
183
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
184
+ end
185
+
186
+ it 'deserializes matrix style object with explode=true' do
187
+ raw_params = { 'filter' => ';role=admin;status=active' }
188
+ param = create_param('filter', 'path', 'matrix', true, 'object', { 'role' => 'string', 'status' => 'string' })
189
+ deserializer = create_deserializer([param])
190
+ result = deserializer.deserialize_path_params(raw_params)
191
+
192
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
193
+ end
194
+
195
+ it 'deserializes matrix style primitive' do
196
+ raw_params = { 'id' => ';id=5' }
197
+ param = create_param('id', 'path', 'matrix', false, 'string', nil)
198
+ deserializer = create_deserializer([param])
199
+ result = deserializer.deserialize_path_params(raw_params)
200
+
201
+ assert_equal({ 'id' => '5' }, result)
202
+ end
203
+
204
+ it 'deserializes headers with simple style' do
205
+ raw_params = { 'X-Filter' => 'role,admin,status,active' }
206
+ param = create_param('X-Filter', 'header', 'simple', false, 'object', { 'role' => 'string', 'status' => 'string' })
207
+ deserializer = create_deserializer([param])
208
+ result = deserializer.deserialize_headers(raw_params)
209
+
210
+ assert_equal({ 'X-Filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
211
+ end
212
+
213
+ it 'handles empty params gracefully' do
214
+ raw_params = {}
215
+ param = create_param('filter', 'query', 'form', true, 'object', { 'role' => 'string' })
216
+ deserializer = create_deserializer([param])
217
+ result = deserializer.deserialize_query_params(raw_params)
218
+
219
+ assert_equal({}, result)
220
+ end
221
+
222
+ it 'handles nil param value' do
223
+ raw_params = { 'filter' => nil }
224
+ param = create_param('filter', 'query', 'form', false, 'object', { 'role' => 'string' })
225
+ deserializer = create_deserializer([param])
226
+ result = deserializer.deserialize_query_params(raw_params)
227
+
228
+ assert_equal({ 'filter' => nil }, result)
229
+ end
230
+
231
+ it 'preserves unknown parameters' do
232
+ raw_params = { 'role' => 'admin', 'unknown' => 'value' }
233
+ param = create_param('filter', 'query', 'form', true, 'object', { 'role' => 'string' })
234
+ deserializer = create_deserializer([param])
235
+ result = deserializer.deserialize_query_params(raw_params)
236
+
237
+ assert_equal 'admin', result[:filter][:role]
238
+ assert_equal 'value', result[:unknown]
239
+ end
240
+
241
+ it 'handles empty object with form style explode=true' do
242
+ raw_params = {}
243
+ param = create_param('filter', 'query', 'form', true, 'object', { 'role' => 'string', 'status' => 'string' })
244
+ deserializer = create_deserializer([param])
245
+ result = deserializer.deserialize_query_params(raw_params)
246
+
247
+ assert_equal({}, result)
248
+ end
249
+
250
+ it 'returns indifferent hashes' do
251
+ raw_params = { 'role' => 'admin' }
252
+ param = create_param('filter', 'query', 'form', true, 'object', { 'role' => 'string' })
253
+ deserializer = create_deserializer([param])
254
+ result = deserializer.deserialize_query_params(raw_params)
255
+
256
+ assert_equal({ 'role' => 'admin' }, result['filter'])
257
+ assert_equal 'admin', result['filter']['role']
258
+ assert_equal({ 'role' => 'admin' }, result[:filter])
259
+ assert_equal 'admin', result[:filter][:role]
260
+ end
261
+
262
+ it 'handles primitive values with form style' do
263
+ raw_params = { 'id' => '123' }
264
+ param = create_param('id', 'query', 'form', false, 'string', nil)
265
+ deserializer = create_deserializer([param])
266
+ result = deserializer.deserialize_query_params(raw_params)
267
+
268
+ assert_equal({ 'id' => '123' }, result)
269
+ end
270
+
271
+ it 'handles primitive values with simple style' do
272
+ raw_params = { 'id' => '123' }
273
+ param = create_param('id', 'path', 'simple', false, 'string', nil)
274
+ deserializer = create_deserializer([param])
275
+ result = deserializer.deserialize_path_params(raw_params)
276
+
277
+ assert_equal({ 'id' => '123' }, result)
278
+ end
279
+
280
+ it 'handles unsupported style gracefully' do
281
+ raw_params = { 'id' => '123' }
282
+ param = Struct.new(:name, :in, :style, :explode, :schema, :required).new('id', 'query', 'unsupported', false, create_schema('string', nil), false)
283
+ deserializer = create_deserializer([param])
284
+ result = deserializer.deserialize_query_params(raw_params)
285
+
286
+ assert_equal({ 'id' => '123' }, result)
287
+ end
288
+
289
+ it 'handles form array when value is already array' do
290
+ raw_params = { 'ids' => ['1', '2', '3'] }
291
+ param = create_param('ids', 'query', 'form', false, 'array', 'integer')
292
+ deserializer = create_deserializer([param])
293
+ result = deserializer.deserialize_query_params(raw_params)
294
+
295
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
296
+ end
297
+
298
+ it 'deserializes label style primitive value' do
299
+ raw_params = { 'id' => '.123' }
300
+ param = create_param('id', 'path', 'label', false, 'string', nil)
301
+ deserializer = create_deserializer([param])
302
+ result = deserializer.deserialize_path_params(raw_params)
303
+
304
+ assert_equal({ 'id' => '123' }, result)
305
+ end
306
+
307
+ it 'handles label style without leading dot' do
308
+ raw_params = { 'id' => '123' }
309
+ param = create_param('id', 'path', 'label', false, 'string', nil)
310
+ deserializer = create_deserializer([param])
311
+ result = deserializer.deserialize_path_params(raw_params)
312
+
313
+ assert_equal({ 'id' => '123' }, result)
314
+ end
315
+
316
+ it 'handles matrix style with missing prefix' do
317
+ raw_params = { 'ids' => 'invalid' }
318
+ param = create_param('ids', 'path', 'matrix', false, 'array', 'integer')
319
+ deserializer = create_deserializer([param])
320
+ result = deserializer.deserialize_path_params(raw_params)
321
+
322
+ assert_equal({ 'ids' => [] }, result)
323
+ end
324
+
325
+ it 'handles matrix style object with missing prefix' do
326
+ raw_params = { 'filter' => 'invalid' }
327
+ param = create_param('filter', 'path', 'matrix', false, 'object', { 'role' => 'string' })
328
+ deserializer = create_deserializer([param])
329
+ result = deserializer.deserialize_path_params(raw_params)
330
+
331
+ assert_equal({ 'filter' => {} }, result)
332
+ end
333
+
334
+ it 'handles matrix style primitive without prefix' do
335
+ raw_params = { 'id' => 'invalid' }
336
+ param = create_param('id', 'path', 'matrix', false, 'string', nil)
337
+ deserializer = create_deserializer([param])
338
+ result = deserializer.deserialize_path_params(raw_params)
339
+
340
+ assert_equal({ 'id' => 'invalid' }, result)
341
+ end
342
+
343
+ it 'handles space delimited when value is already array' do
344
+ raw_params = { 'ids' => ['1', '2', '3'] }
345
+ param = create_param('ids', 'query', 'spaceDelimited', false, 'array', 'integer')
346
+ deserializer = create_deserializer([param])
347
+ result = deserializer.deserialize_query_params(raw_params)
348
+
349
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
350
+ end
351
+
352
+ it 'handles pipe delimited when value is already array' do
353
+ raw_params = { 'ids' => ['1', '2', '3'] }
354
+ param = create_param('ids', 'query', 'pipeDelimited', false, 'array', 'integer')
355
+ deserializer = create_deserializer([param])
356
+ result = deserializer.deserialize_query_params(raw_params)
357
+
358
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
359
+ end
360
+
361
+ it 'handles simple array when value is already array' do
362
+ raw_params = { 'ids' => ['1', '2', '3'] }
363
+ param = create_param('ids', 'path', 'simple', false, 'array', 'integer')
364
+ deserializer = create_deserializer([param])
365
+ result = deserializer.deserialize_path_params(raw_params)
366
+
367
+ assert_equal({ 'ids' => ['1', '2', '3'] }, result)
368
+ end
369
+
370
+ it 'handles comma-separated object with odd number of elements' do
371
+ raw_params = { 'filter' => 'role,admin,status' }
372
+ param = create_param('filter', 'query', 'form', false, 'object', { 'role' => 'string', 'status' => 'string' })
373
+ deserializer = create_deserializer([param])
374
+ result = deserializer.deserialize_query_params(raw_params)
375
+
376
+ assert_equal({ 'filter' => { 'role' => 'admin' } }, result)
377
+ end
378
+
379
+ it 'handles matrix object exploded with malformed pairs' do
380
+ raw_params = { 'filter' => ';role=admin;invalid;status=active' }
381
+ param = create_param('filter', 'path', 'matrix', true, 'object', { 'role' => 'string', 'status' => 'string' })
382
+ deserializer = create_deserializer([param])
383
+ result = deserializer.deserialize_path_params(raw_params)
384
+
385
+ assert_equal({ 'filter' => { 'role' => 'admin', 'status' => 'active' } }, result)
386
+ end
387
+
388
+ it 'handles parameter without schema in simple style' do
389
+ raw_params = { 'id' => '123' }
390
+ param = Struct.new(:name, :in, :style, :explode, :schema, :required).new('id', 'path', 'simple', false, nil, false)
391
+ deserializer = create_deserializer([param])
392
+ result = deserializer.deserialize_path_params(raw_params)
393
+
394
+ assert_equal({ 'id' => '123' }, result)
395
+ end
396
+
397
+ it 'handles parameter without schema in label style' do
398
+ raw_params = { 'id' => '.123' }
399
+ param = Struct.new(:name, :in, :style, :explode, :schema, :required).new('id', 'path', 'label', false, nil, false)
400
+ deserializer = create_deserializer([param])
401
+ result = deserializer.deserialize_path_params(raw_params)
402
+
403
+ assert_equal({ 'id' => '123' }, result)
404
+ end
405
+
406
+ it 'handles parameter without schema in matrix style' do
407
+ raw_params = { 'id' => ';id=123' }
408
+ param = Struct.new(:name, :in, :style, :explode, :schema, :required).new('id', 'path', 'matrix', false, nil, false)
409
+ deserializer = create_deserializer([param])
410
+ result = deserializer.deserialize_path_params(raw_params)
411
+
412
+ assert_equal({ 'id' => ';id=123' }, result)
413
+ end
414
+
415
+ it 'handles parameter without schema in form style' do
416
+ raw_params = { 'id' => '123' }
417
+ param = Struct.new(:name, :in, :style, :explode, :schema, :required).new('id', 'query', 'form', false, nil, false)
418
+ deserializer = create_deserializer([param])
419
+ result = deserializer.deserialize_query_params(raw_params)
420
+
421
+ assert_equal({ 'id' => '123' }, result)
422
+ end
423
+
424
+ it 'handles form explode with symbol property keys' do
425
+ raw_params = { 'role' => 'admin', 'status' => 'active' }
426
+ # Create schema with symbol keys for properties
427
+ schema = Struct.new(:type, :properties, :items).new('object', { role: Struct.new(:type).new('string'), status: Struct.new(:type).new('string') }, nil)
428
+ param = Struct.new(:name, :in, :style, :explode, :schema, :required).new('filter', 'query', 'form', true, schema, false)
429
+ deserializer = create_deserializer([param])
430
+ result = deserializer.deserialize_query_params(raw_params)
431
+
432
+ assert_equal({ 'filter' => { role: 'admin', status: 'active' } }, result)
433
+ end
434
+ end
435
+
436
+ private
437
+
438
+ def create_deserializer(params)
439
+ operation = Struct.new(:operation_object).new(Struct.new(:parameters).new(params))
440
+ Committee::SchemaValidator::OpenAPI3::ParameterDeserializer.new(operation)
441
+ end
442
+
443
+ def create_param(name, location, style, explode, type, properties_or_items)
444
+ Struct.new(:name, :in, :style, :explode, :schema, :required).new(name, location, style, explode, create_schema(type, properties_or_items), false)
445
+ end
446
+
447
+ def create_schema(type, properties_or_items)
448
+ if type == 'object'
449
+ props = properties_or_items.transform_values { |v| Struct.new(:type).new(v) }
450
+ Struct.new(:type, :properties, :items).new(type, props, nil)
451
+ elsif type == 'array'
452
+ Struct.new(:type, :properties, :items).new(type, nil, Struct.new(:type).new(properties_or_items))
453
+ else
454
+ Struct.new(:type, :properties, :items).new(type, nil, nil)
455
+ end
456
+ end
457
+ end
@@ -40,8 +40,7 @@ describe Committee::SchemaValidator::OpenAPI3::RequestValidator do
40
40
  assert_equal 400, last_response.status
41
41
 
42
42
  body = JSON.parse(last_response.body)
43
- message =
44
- %{"Content-Type" request header must be set to any of the following: ["application/json", "application/binary"].}
43
+ message = %{"Content-Type" request header must be set to any of the following: ["application/json", "application/binary"].}
45
44
 
46
45
  assert_equal message, body['message']
47
46
  end
@@ -101,10 +101,7 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
101
101
  end
102
102
 
103
103
  it "passes given an empty date string with allow_empty_date_and_datetime enabled" do
104
- @validator_option = Committee::SchemaValidator::Option.new(
105
- { allow_empty_date_and_datetime: true },
106
- open_api_3_schema,
107
- :open_api_3)
104
+ @validator_option = Committee::SchemaValidator::Option.new({ allow_empty_date_and_datetime: true }, open_api_3_schema, :open_api_3)
108
105
 
109
106
  @path = '/date_time'
110
107
  @method = 'get'
@@ -123,10 +120,7 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
123
120
  end
124
121
 
125
122
  it "passes given an empty date-time string with allow_empty_date_and_datetime enabled" do
126
- @validator_option = Committee::SchemaValidator::Option.new(
127
- { allow_empty_date_and_datetime: true },
128
- open_api_3_schema,
129
- :open_api_3)
123
+ @validator_option = Committee::SchemaValidator::Option.new({ allow_empty_date_and_datetime: true }, open_api_3_schema, :open_api_3)
130
124
 
131
125
  @path = '/date_time'
132
126
  @method = 'get'
@@ -149,8 +143,6 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
149
143
 
150
144
  def call_response_validator(strict = false)
151
145
  @operation_object = open_api_3_schema.operation_object(@path, @method)
152
- Committee::SchemaValidator::OpenAPI3::ResponseValidator.
153
- new(@operation_object, @validator_option).
154
- call(@status, @headers, @data, strict)
146
+ Committee::SchemaValidator::OpenAPI3::ResponseValidator.new(@operation_object, @validator_option).call(@status, @headers, @data, strict)
155
147
  end
156
148
  end
@@ -20,4 +20,45 @@ describe Committee::SchemaValidator do
20
20
  media_type = Committee::SchemaValidator.request_media_type(request)
21
21
  assert_equal 'multipart/form-data', media_type
22
22
  end
23
+
24
+ it "detects application/json as a JSON media type" do
25
+ assert_equal true, Committee::SchemaValidator.json_media_type?("application/json")
26
+ end
27
+
28
+ it "detects application/problem+json with parameters as a JSON media type" do
29
+ assert_equal true, Committee::SchemaValidator.json_media_type?("application/problem+json; charset=utf-8")
30
+ end
31
+
32
+ it "detects application/vnd.api+json as a JSON media type" do
33
+ assert_equal true, Committee::SchemaValidator.json_media_type?("application/vnd.api+json")
34
+ end
35
+
36
+ it "does not detect application/x-ndjson as a JSON media type" do
37
+ assert_equal false, Committee::SchemaValidator.json_media_type?("application/x-ndjson")
38
+ end
39
+
40
+ it "does not detect non-JSON content types as JSON media types" do
41
+ assert_equal false, Committee::SchemaValidator.json_media_type?("test/csv")
42
+ assert_equal false, Committee::SchemaValidator.json_media_type?(nil)
43
+ end
44
+
45
+ it "parses +json responses in the HyperSchema validator" do
46
+ schema = Committee::Drivers::OpenAPI2::Driver.new.parse(open_api_2_data)
47
+ validator_option = Committee::SchemaValidator::Option.new({ parse_response_by_content_type: true }, schema, :hyper_schema)
48
+ router = Committee::SchemaValidator::HyperSchema::Router.new(schema, validator_option)
49
+ request = Rack::Request.new({ "REQUEST_METHOD" => "GET", "PATH_INFO" => "/api/pets", "rack.input" => StringIO.new("") })
50
+ validator = Committee::SchemaValidator::HyperSchema.new(router, request, validator_option)
51
+
52
+ validator.link.media_type = "application/vnd.api+json"
53
+
54
+ validator.response_validate(200, { "Content-Type" => "application/vnd.api+json" }, [JSON.generate([ValidPet])])
55
+ end
56
+
57
+ it "builds prefix regexp with a path segment boundary" do
58
+ regexp = Committee::SchemaValidator.build_prefix_regexp("/v1")
59
+
60
+ assert regexp.match?("/v1")
61
+ assert regexp.match?("/v1/characters")
62
+ refute regexp.match?("/v11/characters")
63
+ end
23
64
  end