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.
- checksums.yaml +4 -4
- data/lib/committee/drivers/open_api_3/driver.rb +7 -1
- data/lib/committee/drivers.rb +2 -3
- data/lib/committee/errors.rb +11 -0
- data/lib/committee/middleware/base.rb +11 -5
- data/lib/committee/middleware/options/base.rb +107 -0
- data/lib/committee/middleware/options/request_validation.rb +80 -0
- data/lib/committee/middleware/options/response_validation.rb +46 -0
- data/lib/committee/middleware/options.rb +12 -0
- data/lib/committee/middleware/request_validation.rb +7 -1
- data/lib/committee/middleware/response_validation.rb +6 -2
- data/lib/committee/middleware.rb +1 -0
- data/lib/committee/schema_validator/hyper_schema/response_generator.rb +1 -3
- data/lib/committee/schema_validator/hyper_schema/response_validator.rb +14 -1
- data/lib/committee/schema_validator/hyper_schema/router.rb +1 -1
- data/lib/committee/schema_validator/hyper_schema.rb +3 -14
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +43 -13
- data/lib/committee/schema_validator/open_api_3/parameter_deserializer.rb +556 -0
- data/lib/committee/schema_validator/open_api_3/response_validator.rb +16 -2
- data/lib/committee/schema_validator/open_api_3.rb +19 -13
- data/lib/committee/schema_validator/option.rb +6 -17
- data/lib/committee/schema_validator.rb +12 -1
- data/lib/committee/test/except_parameter.rb +416 -0
- data/lib/committee/test/methods.rb +38 -2
- data/lib/committee/version.rb +1 -1
- data/lib/committee.rb +1 -1
- data/test/drivers/open_api_2/driver_test.rb +4 -16
- data/test/drivers/open_api_2/parameter_schema_builder_test.rb +4 -50
- data/test/drivers_test.rb +35 -21
- data/test/middleware/options/base_test.rb +120 -0
- data/test/middleware/options/request_validation_test.rb +177 -0
- data/test/middleware/options/response_validation_test.rb +121 -0
- data/test/middleware/request_validation_open_api_3_test.rb +200 -80
- data/test/middleware/request_validation_test.rb +13 -70
- data/test/middleware/response_validation_open_api_3_test.rb +40 -17
- data/test/middleware/response_validation_test.rb +3 -14
- data/test/request_unpacker_test.rb +2 -10
- data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +1 -37
- data/test/schema_validator/hyper_schema/request_validator_test.rb +6 -30
- data/test/schema_validator/hyper_schema/router_test.rb +5 -0
- data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +1 -37
- data/test/schema_validator/open_api_3/operation_wrapper_test.rb +58 -43
- data/test/schema_validator/open_api_3/parameter_deserializer_test.rb +457 -0
- data/test/schema_validator/open_api_3/request_validator_test.rb +1 -2
- data/test/schema_validator/open_api_3/response_validator_test.rb +3 -11
- data/test/schema_validator_test.rb +41 -0
- data/test/test/methods_test.rb +238 -105
- data/test/test/schema_coverage_test.rb +8 -155
- 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
|