committee 5.6.1 → 5.6.2
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 +5 -0
- 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 +2 -13
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +43 -13
- data/lib/committee/schema_validator/open_api_3/parameter_deserializer.rb +495 -0
- data/lib/committee/schema_validator/open_api_3/response_validator.rb +16 -2
- data/lib/committee/schema_validator/open_api_3.rb +18 -12
- data/lib/committee/schema_validator/option.rb +6 -17
- data/lib/committee/schema_validator.rb +5 -1
- data/lib/committee/test/except_parameter.rb +416 -0
- data/lib/committee/test/methods.rb +27 -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 +113 -80
- data/test/middleware/request_validation_test.rb +13 -70
- data/test/middleware/response_validation_open_api_3_test.rb +33 -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 +40 -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 +8 -0
- data/test/test/methods_test.rb +222 -105
- data/test/test/schema_coverage_test.rb +8 -155
- metadata +12 -2
|
@@ -53,43 +53,7 @@ describe Committee::SchemaValidator::HyperSchema::StringParamsCoercer do
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
it "pass array property" do
|
|
56
|
-
params = {
|
|
57
|
-
"array_property" => [
|
|
58
|
-
{
|
|
59
|
-
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
|
60
|
-
"per_page" => "1",
|
|
61
|
-
"nested_coercer_object" => {
|
|
62
|
-
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
|
63
|
-
"threshold" => "1.5"
|
|
64
|
-
},
|
|
65
|
-
"nested_no_coercer_object" => {
|
|
66
|
-
"per_page" => "1",
|
|
67
|
-
"threshold" => "1.5"
|
|
68
|
-
},
|
|
69
|
-
"nested_coercer_array" => [
|
|
70
|
-
{
|
|
71
|
-
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
|
72
|
-
"threshold" => "1.5"
|
|
73
|
-
}
|
|
74
|
-
],
|
|
75
|
-
"nested_no_coercer_array" => [
|
|
76
|
-
{
|
|
77
|
-
"per_page" => "1",
|
|
78
|
-
"threshold" => "1.5"
|
|
79
|
-
}
|
|
80
|
-
]
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
|
84
|
-
"per_page" => "1",
|
|
85
|
-
"threshold" => "1.5"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"threshold" => "1.5",
|
|
89
|
-
"per_page" => "1"
|
|
90
|
-
}
|
|
91
|
-
],
|
|
92
|
-
}
|
|
56
|
+
params = { "array_property" => [{ "update_time" => "2016-04-01T16:00:00.000+09:00", "per_page" => "1", "nested_coercer_object" => { "update_time" => "2016-04-01T16:00:00.000+09:00", "threshold" => "1.5" }, "nested_no_coercer_object" => { "per_page" => "1", "threshold" => "1.5" }, "nested_coercer_array" => [{ "update_time" => "2016-04-01T16:00:00.000+09:00", "threshold" => "1.5" }], "nested_no_coercer_array" => [{ "per_page" => "1", "threshold" => "1.5" }] }, { "update_time" => "2016-04-01T16:00:00.000+09:00", "per_page" => "1", "threshold" => "1.5" }, { "threshold" => "1.5", "per_page" => "1" }], }
|
|
93
57
|
call(params, coerce_recursive: true)
|
|
94
58
|
|
|
95
59
|
first_data = params["array_property"][0]
|
|
@@ -18,13 +18,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
|
18
18
|
|
|
19
19
|
HEADER = { 'Content-Type' => 'application/json' }
|
|
20
20
|
|
|
21
|
-
SCHEMA_PROPERTIES_PAIR = [
|
|
22
|
-
['string', 'str'],
|
|
23
|
-
['integer', 1],
|
|
24
|
-
['boolean', true],
|
|
25
|
-
['boolean', false],
|
|
26
|
-
['number', 0.1],
|
|
27
|
-
]
|
|
21
|
+
SCHEMA_PROPERTIES_PAIR = [['string', 'str'], ['integer', 1], ['boolean', true], ['boolean', false], ['number', 0.1],]
|
|
28
22
|
|
|
29
23
|
it 'correct data' do
|
|
30
24
|
operation_object.validate_request_params({}, {}, SCHEMA_PROPERTIES_PAIR.to_h, HEADER, @validator_option)
|
|
@@ -32,20 +26,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
|
32
26
|
end
|
|
33
27
|
|
|
34
28
|
it 'correct object data' do
|
|
35
|
-
operation_object.validate_request_params(
|
|
36
|
-
{},
|
|
37
|
-
{},
|
|
38
|
-
{
|
|
39
|
-
"object_1" =>
|
|
40
|
-
{
|
|
41
|
-
"string_1" => nil,
|
|
42
|
-
"integer_1" => nil,
|
|
43
|
-
"boolean_1" => nil,
|
|
44
|
-
"number_1" => nil
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
HEADER,
|
|
48
|
-
@validator_option)
|
|
29
|
+
operation_object.validate_request_params({}, {}, { "object_1" => { "string_1" => nil, "integer_1" => nil, "boolean_1" => nil, "number_1" => nil } }, HEADER, @validator_option)
|
|
49
30
|
|
|
50
31
|
assert true
|
|
51
32
|
end
|
|
@@ -93,21 +74,9 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
|
93
74
|
end
|
|
94
75
|
|
|
95
76
|
it 'correct' do
|
|
96
|
-
operation_object.validate_request_params(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
{},
|
|
100
|
-
HEADER,
|
|
101
|
-
@validator_option
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
operation_object.validate_request_params(
|
|
105
|
-
{},
|
|
106
|
-
{ "query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1 },
|
|
107
|
-
{},
|
|
108
|
-
HEADER,
|
|
109
|
-
@validator_option
|
|
110
|
-
)
|
|
77
|
+
operation_object.validate_request_params({}, { "query_string" => "query", "query_integer_list" => [1, 2] }, {}, HEADER, @validator_option)
|
|
78
|
+
|
|
79
|
+
operation_object.validate_request_params({}, { "query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1 }, {}, HEADER, @validator_option)
|
|
111
80
|
|
|
112
81
|
assert true
|
|
113
82
|
end
|
|
@@ -123,13 +92,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
|
123
92
|
|
|
124
93
|
it 'invalid type' do
|
|
125
94
|
e = assert_raises(Committee::InvalidRequest) {
|
|
126
|
-
operation_object.validate_request_params(
|
|
127
|
-
{},
|
|
128
|
-
{ "query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1 },
|
|
129
|
-
{},
|
|
130
|
-
HEADER,
|
|
131
|
-
@validator_option
|
|
132
|
-
)
|
|
95
|
+
operation_object.validate_request_params({}, { "query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1 }, {}, HEADER, @validator_option)
|
|
133
96
|
}
|
|
134
97
|
|
|
135
98
|
assert_match(/expected string, but received Integer: 1/i, e.message)
|
|
@@ -208,5 +171,39 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
|
208
171
|
assert_equal [], operation_object.request_content_types
|
|
209
172
|
end
|
|
210
173
|
end
|
|
174
|
+
|
|
175
|
+
describe 'coercion option wiring' do
|
|
176
|
+
before do
|
|
177
|
+
@path = '/coerce_path_params/1'
|
|
178
|
+
@method = 'get'
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'uses coerce_path_params for explicit path coercion' do
|
|
182
|
+
disabled = Committee::SchemaValidator::Option.new({ coerce_path_params: false, coerce_query_params: true }, open_api_3_schema, :open_api_3)
|
|
183
|
+
enabled = Committee::SchemaValidator::Option.new({ coerce_path_params: true, coerce_query_params: false }, open_api_3_schema, :open_api_3)
|
|
184
|
+
|
|
185
|
+
error = assert_raises(Committee::InvalidRequest) do
|
|
186
|
+
operation_object.coerce_path_parameter(disabled)
|
|
187
|
+
end
|
|
188
|
+
assert_match(/expected integer, but received String: "1"/i, error.message)
|
|
189
|
+
|
|
190
|
+
coerced = operation_object.coerce_path_parameter(enabled)
|
|
191
|
+
assert_kind_of(Integer, coerced['integer'])
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it 'uses coerce_query_params for request parameter validation' do
|
|
195
|
+
query_coercion_disabled = Committee::SchemaValidator::Option.new({ coerce_query_params: false }, open_api_3_schema, :open_api_3)
|
|
196
|
+
query_coercion_enabled = Committee::SchemaValidator::Option.new({ coerce_query_params: true }, open_api_3_schema, :open_api_3)
|
|
197
|
+
|
|
198
|
+
error = assert_raises(Committee::InvalidRequest) do
|
|
199
|
+
@path = '/characters'
|
|
200
|
+
operation_object.validate_request_params({}, { "limit" => "1" }, {}, HEADER, query_coercion_disabled)
|
|
201
|
+
end
|
|
202
|
+
assert_match(/expected integer, but received String: "1"/i, error.message)
|
|
203
|
+
|
|
204
|
+
@path = '/characters'
|
|
205
|
+
operation_object.validate_request_params({}, { "limit" => "1" }, {}, HEADER, query_coercion_enabled)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
211
208
|
end
|
|
212
209
|
end
|
|
@@ -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
|