grape 1.8.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +19 -22
- data/UPGRADING.md +35 -0
- data/grape.gemspec +1 -4
- data/lib/grape/dsl/desc.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +9 -9
- data/lib/grape/endpoint.rb +9 -1
- data/lib/grape/exceptions/missing_group_type.rb +1 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
- data/lib/grape/http/headers.rb +12 -2
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/error.rb +4 -4
- data/lib/grape/middleware/formatter.rb +5 -5
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +8 -2
- data/lib/grape/router/route.rb +1 -1
- data/lib/grape/validations/validators/base.rb +1 -1
- data/lib/grape/validations/validators/values_validator.rb +2 -2
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +15 -2
- metadata +8 -243
- data/spec/grape/api/custom_validations_spec.rb +0 -213
- data/spec/grape/api/deeply_included_options_spec.rb +0 -56
- data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
- data/spec/grape/api/documentation_spec.rb +0 -59
- data/spec/grape/api/inherited_helpers_spec.rb +0 -114
- data/spec/grape/api/instance_spec.rb +0 -103
- data/spec/grape/api/invalid_format_spec.rb +0 -45
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
- data/spec/grape/api/nested_helpers_spec.rb +0 -50
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
- data/spec/grape/api/parameters_modification_spec.rb +0 -41
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
- data/spec/grape/api/recognize_path_spec.rb +0 -21
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
- data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
- data/spec/grape/api/shared_helpers_spec.rb +0 -36
- data/spec/grape/api_remount_spec.rb +0 -509
- data/spec/grape/api_spec.rb +0 -4356
- data/spec/grape/dsl/callbacks_spec.rb +0 -45
- data/spec/grape/dsl/desc_spec.rb +0 -98
- data/spec/grape/dsl/headers_spec.rb +0 -62
- data/spec/grape/dsl/helpers_spec.rb +0 -100
- data/spec/grape/dsl/inside_route_spec.rb +0 -531
- data/spec/grape/dsl/logger_spec.rb +0 -24
- data/spec/grape/dsl/middleware_spec.rb +0 -60
- data/spec/grape/dsl/parameters_spec.rb +0 -180
- data/spec/grape/dsl/request_response_spec.rb +0 -225
- data/spec/grape/dsl/routing_spec.rb +0 -275
- data/spec/grape/dsl/settings_spec.rb +0 -261
- data/spec/grape/dsl/validations_spec.rb +0 -55
- data/spec/grape/endpoint/declared_spec.rb +0 -846
- data/spec/grape/endpoint_spec.rb +0 -1085
- data/spec/grape/entity_spec.rb +0 -336
- data/spec/grape/exceptions/base_spec.rb +0 -81
- data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
- data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_option_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
- data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
- data/spec/grape/exceptions/validation_spec.rb +0 -19
- data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
- data/spec/grape/grape_spec.rb +0 -9
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
- data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
- data/spec/grape/integration/rack_spec.rb +0 -51
- data/spec/grape/loading_spec.rb +0 -44
- data/spec/grape/middleware/auth/base_spec.rb +0 -31
- data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
- data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
- data/spec/grape/middleware/base_spec.rb +0 -221
- data/spec/grape/middleware/error_spec.rb +0 -85
- data/spec/grape/middleware/exception_spec.rb +0 -294
- data/spec/grape/middleware/formatter_spec.rb +0 -461
- data/spec/grape/middleware/globals_spec.rb +0 -30
- data/spec/grape/middleware/stack_spec.rb +0 -155
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
- data/spec/grape/middleware/versioner/header_spec.rb +0 -345
- data/spec/grape/middleware/versioner/param_spec.rb +0 -171
- data/spec/grape/middleware/versioner/path_spec.rb +0 -62
- data/spec/grape/middleware/versioner_spec.rb +0 -21
- data/spec/grape/named_api_spec.rb +0 -19
- data/spec/grape/parser_spec.rb +0 -86
- data/spec/grape/path_spec.rb +0 -252
- data/spec/grape/presenters/presenter_spec.rb +0 -71
- data/spec/grape/request_spec.rb +0 -126
- data/spec/grape/util/inheritable_setting_spec.rb +0 -242
- data/spec/grape/util/inheritable_values_spec.rb +0 -79
- data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
- data/spec/grape/util/stackable_values_spec.rb +0 -128
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
- data/spec/grape/validations/attributes_doc_spec.rb +0 -153
- data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
- data/spec/grape/validations/params_scope_spec.rb +0 -1420
- data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
- data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
- data/spec/grape/validations/types_spec.rb +0 -111
- data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
- data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
- data/spec/grape/validations/validators/base_spec.rb +0 -38
- data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
- data/spec/grape/validations/validators/default_spec.rb +0 -463
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
- data/spec/grape/validations/validators/except_values_spec.rb +0 -192
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
- data/spec/grape/validations/validators/presence_spec.rb +0 -315
- data/spec/grape/validations/validators/regexp_spec.rb +0 -161
- data/spec/grape/validations/validators/same_as_spec.rb +0 -57
- data/spec/grape/validations/validators/values_spec.rb +0 -733
- data/spec/grape/validations/validators/zh-CN.yml +0 -10
- data/spec/grape/validations_spec.rb +0 -2030
- data/spec/integration/eager_load/eager_load_spec.rb +0 -15
- data/spec/integration/multi_json/json_spec.rb +0 -7
- data/spec/integration/multi_xml/xml_spec.rb +0 -7
- data/spec/shared/deprecated_class_examples.rb +0 -16
- data/spec/shared/versioning_examples.rb +0 -215
- data/spec/spec_helper.rb +0 -52
- data/spec/support/basic_auth_encode_helpers.rb +0 -11
- data/spec/support/chunks.rb +0 -14
- data/spec/support/content_type_helpers.rb +0 -15
- data/spec/support/endpoint_faker.rb +0 -25
- data/spec/support/file_streamer.rb +0 -13
- data/spec/support/integer_helpers.rb +0 -13
- data/spec/support/versioned_helpers.rb +0 -55
@@ -1,463 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Validations::Validators::DefaultValidator do
|
4
|
-
let_it_be(:app) do
|
5
|
-
Class.new(Grape::API) do
|
6
|
-
default_format :json
|
7
|
-
|
8
|
-
params do
|
9
|
-
optional :id
|
10
|
-
optional :type, default: 'default-type'
|
11
|
-
end
|
12
|
-
get '/' do
|
13
|
-
{ id: params[:id], type: params[:type] }
|
14
|
-
end
|
15
|
-
|
16
|
-
params do
|
17
|
-
optional :type1, default: 'default-type1'
|
18
|
-
optional :type2, default: 'default-type2'
|
19
|
-
end
|
20
|
-
get '/user' do
|
21
|
-
{ type1: params[:type1], type2: params[:type2] }
|
22
|
-
end
|
23
|
-
|
24
|
-
params do
|
25
|
-
requires :id
|
26
|
-
optional :type1, default: 'default-type1'
|
27
|
-
optional :type2, default: 'default-type2'
|
28
|
-
end
|
29
|
-
|
30
|
-
get '/message' do
|
31
|
-
{ id: params[:id], type1: params[:type1], type2: params[:type2] }
|
32
|
-
end
|
33
|
-
|
34
|
-
params do
|
35
|
-
optional :random, default: -> { Random.rand }
|
36
|
-
optional :not_random, default: Random.rand
|
37
|
-
end
|
38
|
-
get '/numbers' do
|
39
|
-
{ random_number: params[:random], non_random_number: params[:non_random_number] }
|
40
|
-
end
|
41
|
-
|
42
|
-
params do
|
43
|
-
optional :array, type: Array do
|
44
|
-
requires :name
|
45
|
-
optional :with_default, default: 'default'
|
46
|
-
end
|
47
|
-
end
|
48
|
-
get '/array' do
|
49
|
-
{ array: params[:array] }
|
50
|
-
end
|
51
|
-
|
52
|
-
params do
|
53
|
-
requires :thing1
|
54
|
-
optional :more_things, type: Array do
|
55
|
-
requires :nested_thing
|
56
|
-
requires :other_thing, default: 1
|
57
|
-
end
|
58
|
-
end
|
59
|
-
get '/optional_array' do
|
60
|
-
{ thing1: params[:thing1] }
|
61
|
-
end
|
62
|
-
|
63
|
-
params do
|
64
|
-
requires :root, type: Hash do
|
65
|
-
optional :some_things, type: Array do
|
66
|
-
requires :foo
|
67
|
-
optional :options, type: Array do
|
68
|
-
requires :name, type: String
|
69
|
-
requires :value, type: String
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
get '/nested_optional_array' do
|
75
|
-
{ root: params[:root] }
|
76
|
-
end
|
77
|
-
|
78
|
-
params do
|
79
|
-
requires :root, type: Hash do
|
80
|
-
optional :some_things, type: Array do
|
81
|
-
requires :foo
|
82
|
-
optional :options, type: Array do
|
83
|
-
optional :name, type: String
|
84
|
-
optional :value, type: String
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
get '/another_nested_optional_array' do
|
90
|
-
{ root: params[:root] }
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'lets you leave required values nested inside an optional blank' do
|
96
|
-
get '/optional_array', thing1: 'stuff'
|
97
|
-
expect(last_response.status).to eq(200)
|
98
|
-
expect(last_response.body).to eq({ thing1: 'stuff' }.to_json)
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'allows optional arrays to be omitted' do
|
102
|
-
params = { some_things:
|
103
|
-
[{ foo: 'one', options: [{ name: 'wat', value: 'nope' }] },
|
104
|
-
{ foo: 'two' },
|
105
|
-
{ foo: 'three', options: [{ name: 'wooop', value: 'yap' }] }] }
|
106
|
-
get '/nested_optional_array', root: params
|
107
|
-
expect(last_response.status).to eq(200)
|
108
|
-
expect(last_response.body).to eq({ root: params }.to_json)
|
109
|
-
end
|
110
|
-
|
111
|
-
it 'does not allows faulty optional arrays' do
|
112
|
-
params = { some_things:
|
113
|
-
[
|
114
|
-
{ foo: 'one', options: [{ name: 'wat', value: 'nope' }] },
|
115
|
-
{ foo: 'two', options: [{ name: 'wat' }] },
|
116
|
-
{ foo: 'three' }
|
117
|
-
] }
|
118
|
-
error = { error: 'root[some_things][1][options][0][value] is missing' }
|
119
|
-
get '/nested_optional_array', root: params
|
120
|
-
expect(last_response.status).to eq(400)
|
121
|
-
expect(last_response.body).to eq(error.to_json)
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'allows optional arrays with optional params' do
|
125
|
-
params = { some_things:
|
126
|
-
[
|
127
|
-
{ foo: 'one', options: [{ value: 'nope' }] },
|
128
|
-
{ foo: 'two', options: [{ name: 'wat' }] },
|
129
|
-
{ foo: 'three' }
|
130
|
-
] }
|
131
|
-
get '/another_nested_optional_array', root: params
|
132
|
-
expect(last_response.status).to eq(200)
|
133
|
-
expect(last_response.body).to eq({ root: params }.to_json)
|
134
|
-
end
|
135
|
-
|
136
|
-
it 'set default value for optional param' do
|
137
|
-
get('/')
|
138
|
-
expect(last_response.status).to eq(200)
|
139
|
-
expect(last_response.body).to eq({ id: nil, type: 'default-type' }.to_json)
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'set default values for optional params' do
|
143
|
-
get('/user')
|
144
|
-
expect(last_response.status).to eq(200)
|
145
|
-
expect(last_response.body).to eq({ type1: 'default-type1', type2: 'default-type2' }.to_json)
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'set default values for missing params in the request' do
|
149
|
-
get('/user?type2=value2')
|
150
|
-
expect(last_response.status).to eq(200)
|
151
|
-
expect(last_response.body).to eq({ type1: 'default-type1', type2: 'value2' }.to_json)
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'set default values for optional params and allow to use required fields in the same time' do
|
155
|
-
get('/message?id=1')
|
156
|
-
expect(last_response.status).to eq(200)
|
157
|
-
expect(last_response.body).to eq({ id: '1', type1: 'default-type1', type2: 'default-type2' }.to_json)
|
158
|
-
end
|
159
|
-
|
160
|
-
it 'sets lambda based defaults at the time of call' do
|
161
|
-
get('/numbers')
|
162
|
-
expect(last_response.status).to eq(200)
|
163
|
-
before = JSON.parse(last_response.body)
|
164
|
-
get('/numbers')
|
165
|
-
expect(last_response.status).to eq(200)
|
166
|
-
after = JSON.parse(last_response.body)
|
167
|
-
|
168
|
-
expect(before['non_random_number']).to eq(after['non_random_number'])
|
169
|
-
expect(before['random_number']).not_to eq(after['random_number'])
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'sets default values for grouped arrays' do
|
173
|
-
get('/array?array[][name]=name&array[][name]=name2&array[][with_default]=bar2')
|
174
|
-
expect(last_response.status).to eq(200)
|
175
|
-
expect(last_response.body).to eq({ array: [{ name: 'name', with_default: 'default' }, { name: 'name2', with_default: 'bar2' }] }.to_json)
|
176
|
-
end
|
177
|
-
|
178
|
-
context 'optional group with defaults' do
|
179
|
-
subject do
|
180
|
-
Class.new(Grape::API) do
|
181
|
-
default_format :json
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def app
|
186
|
-
subject
|
187
|
-
end
|
188
|
-
|
189
|
-
context 'optional array without default value includes optional param with default value' do
|
190
|
-
before do
|
191
|
-
subject.params do
|
192
|
-
optional :optional_array, type: Array do
|
193
|
-
optional :foo_in_optional_array, default: 'bar'
|
194
|
-
end
|
195
|
-
end
|
196
|
-
subject.post '/optional_array' do
|
197
|
-
{ optional_array: params[:optional_array] }
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
it 'returns nil for optional array if param is not provided' do
|
202
|
-
post '/optional_array'
|
203
|
-
expect(last_response.status).to eq(201)
|
204
|
-
expect(last_response.body).to eq({ optional_array: nil }.to_json)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
context 'optional array with default value includes optional param with default value' do
|
209
|
-
before do
|
210
|
-
subject.params do
|
211
|
-
optional :optional_array_with_default, type: Array, default: [] do
|
212
|
-
optional :foo_in_optional_array, default: 'bar'
|
213
|
-
end
|
214
|
-
end
|
215
|
-
subject.post '/optional_array_with_default' do
|
216
|
-
{ optional_array_with_default: params[:optional_array_with_default] }
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'sets default value for optional array if param is not provided' do
|
221
|
-
post '/optional_array_with_default'
|
222
|
-
expect(last_response.status).to eq(201)
|
223
|
-
expect(last_response.body).to eq({ optional_array_with_default: [] }.to_json)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
context 'optional hash without default value includes optional param with default value' do
|
228
|
-
before do
|
229
|
-
subject.params do
|
230
|
-
optional :optional_hash_without_default, type: Hash do
|
231
|
-
optional :foo_in_optional_hash, default: 'bar'
|
232
|
-
end
|
233
|
-
end
|
234
|
-
subject.post '/optional_hash_without_default' do
|
235
|
-
{ optional_hash_without_default: params[:optional_hash_without_default] }
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
it 'returns nil for optional hash if param is not provided' do
|
240
|
-
post '/optional_hash_without_default'
|
241
|
-
expect(last_response.status).to eq(201)
|
242
|
-
expect(last_response.body).to eq({ optional_hash_without_default: nil }.to_json)
|
243
|
-
end
|
244
|
-
|
245
|
-
it 'does not fail even if invalid params is passed to default validator' do
|
246
|
-
expect { post '/optional_hash_without_default', optional_hash_without_default: '5678' }.not_to raise_error
|
247
|
-
expect(last_response.status).to eq(400)
|
248
|
-
expect(last_response.body).to eq({ error: 'optional_hash_without_default is invalid' }.to_json)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
context 'optional hash with default value includes optional param with default value' do
|
253
|
-
before do
|
254
|
-
subject.params do
|
255
|
-
optional :optional_hash_with_default, type: Hash, default: {} do
|
256
|
-
optional :foo_in_optional_hash, default: 'bar'
|
257
|
-
end
|
258
|
-
end
|
259
|
-
subject.post '/optional_hash_with_default_empty_hash' do
|
260
|
-
{ optional_hash_with_default: params[:optional_hash_with_default] }
|
261
|
-
end
|
262
|
-
|
263
|
-
subject.params do
|
264
|
-
optional :optional_hash_with_default, type: Hash, default: { foo_in_optional_hash: 'parent_default' } do
|
265
|
-
optional :some_param
|
266
|
-
optional :foo_in_optional_hash, default: 'own_default'
|
267
|
-
end
|
268
|
-
end
|
269
|
-
subject.post '/optional_hash_with_default_inner_params' do
|
270
|
-
{ foo_in_optional_hash: params[:optional_hash_with_default][:foo_in_optional_hash] }
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
it 'sets default value for optional hash if param is not provided' do
|
275
|
-
post '/optional_hash_with_default_empty_hash'
|
276
|
-
expect(last_response.status).to eq(201)
|
277
|
-
expect(last_response.body).to eq({ optional_hash_with_default: {} }.to_json)
|
278
|
-
end
|
279
|
-
|
280
|
-
it 'sets default value from parent defaults for inner param if parent param is not provided' do
|
281
|
-
post '/optional_hash_with_default_inner_params'
|
282
|
-
expect(last_response.status).to eq(201)
|
283
|
-
expect(last_response.body).to eq({ foo_in_optional_hash: 'parent_default' }.to_json)
|
284
|
-
end
|
285
|
-
|
286
|
-
it 'sets own default value for inner param if parent param is provided' do
|
287
|
-
post '/optional_hash_with_default_inner_params', optional_hash_with_default: { some_param: 'param' }
|
288
|
-
expect(last_response.status).to eq(201)
|
289
|
-
expect(last_response.body).to eq({ foo_in_optional_hash: 'own_default' }.to_json)
|
290
|
-
end
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
context 'optional with nil as value' do
|
295
|
-
subject do
|
296
|
-
Class.new(Grape::API) do
|
297
|
-
default_format :json
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def app
|
302
|
-
subject
|
303
|
-
end
|
304
|
-
|
305
|
-
context 'primitive types' do
|
306
|
-
[
|
307
|
-
[Integer, 0],
|
308
|
-
[Integer, 42],
|
309
|
-
[Float, 0.0],
|
310
|
-
[Float, 4.2],
|
311
|
-
[BigDecimal, 0.0],
|
312
|
-
[BigDecimal, 4.2],
|
313
|
-
[Numeric, 0],
|
314
|
-
[Numeric, 42],
|
315
|
-
[Date, Date.today],
|
316
|
-
[DateTime, DateTime.now],
|
317
|
-
[Time, Time.now],
|
318
|
-
[Time, Time.at(0)],
|
319
|
-
[Grape::API::Boolean, false],
|
320
|
-
[String, ''],
|
321
|
-
[String, 'non-empty-string'],
|
322
|
-
[Symbol, :symbol],
|
323
|
-
[TrueClass, true],
|
324
|
-
[FalseClass, false]
|
325
|
-
].each do |type, default|
|
326
|
-
it 'respects the default value' do
|
327
|
-
subject.params do
|
328
|
-
optional :param, type: type, default: default
|
329
|
-
end
|
330
|
-
subject.get '/default_value' do
|
331
|
-
params[:param]
|
332
|
-
end
|
333
|
-
|
334
|
-
get '/default_value', param: nil
|
335
|
-
expect(last_response.status).to eq(200)
|
336
|
-
expect(last_response.body).to eq(default.to_json)
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
context 'structures types' do
|
342
|
-
[
|
343
|
-
[Hash, {}],
|
344
|
-
[Hash, { test: 'non-empty' }],
|
345
|
-
[Array, []],
|
346
|
-
[Array, ['non-empty']],
|
347
|
-
[Array[Integer], []],
|
348
|
-
[Set, []],
|
349
|
-
[Set, [1]]
|
350
|
-
].each do |type, default|
|
351
|
-
it 'respects the default value' do
|
352
|
-
subject.params do
|
353
|
-
optional :param, type: type, default: default
|
354
|
-
end
|
355
|
-
subject.get '/default_value' do
|
356
|
-
params[:param]
|
357
|
-
end
|
358
|
-
|
359
|
-
get '/default_value', param: nil
|
360
|
-
expect(last_response.status).to eq(200)
|
361
|
-
expect(last_response.body).to eq(default.to_json)
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
context 'special types' do
|
367
|
-
[
|
368
|
-
[JSON, ''],
|
369
|
-
[JSON, { test: 'non-empty-string' }.to_json],
|
370
|
-
[Array[JSON], []],
|
371
|
-
[Array[JSON], [{ test: 'non-empty-string' }.to_json]],
|
372
|
-
[::File, ''],
|
373
|
-
[::File, { test: 'non-empty-string' }.to_json],
|
374
|
-
[Rack::Multipart::UploadedFile, ''],
|
375
|
-
[Rack::Multipart::UploadedFile, { test: 'non-empty-string' }.to_json]
|
376
|
-
].each do |type, default|
|
377
|
-
it 'respects the default value' do
|
378
|
-
subject.params do
|
379
|
-
optional :param, type: type, default: default
|
380
|
-
end
|
381
|
-
subject.get '/default_value' do
|
382
|
-
params[:param]
|
383
|
-
end
|
384
|
-
|
385
|
-
get '/default_value', param: nil
|
386
|
-
expect(last_response.status).to eq(200)
|
387
|
-
expect(last_response.body).to eq(default.to_json)
|
388
|
-
end
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
context 'variant-member-type collections' do
|
393
|
-
[
|
394
|
-
[Array[Integer, String], [0, '']],
|
395
|
-
[Array[Integer, String], [42, 'non-empty-string']],
|
396
|
-
[[Integer, String, Array[Integer, String]], [0, '', [0, '']]],
|
397
|
-
[[Integer, String, Array[Integer, String]], [42, 'non-empty-string', [42, 'non-empty-string']]]
|
398
|
-
].each do |type, default|
|
399
|
-
it 'respects the default value' do
|
400
|
-
subject.params do
|
401
|
-
optional :param, type: type, default: default
|
402
|
-
end
|
403
|
-
subject.get '/default_value' do
|
404
|
-
params[:param]
|
405
|
-
end
|
406
|
-
|
407
|
-
get '/default_value', param: nil
|
408
|
-
expect(last_response.status).to eq(200)
|
409
|
-
expect(last_response.body).to eq(default.to_json)
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
context 'array with default values and given conditions' do
|
416
|
-
subject do
|
417
|
-
Class.new(Grape::API) do
|
418
|
-
default_format :json
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
def app
|
423
|
-
subject
|
424
|
-
end
|
425
|
-
|
426
|
-
it 'applies the default values only if the conditions are met' do
|
427
|
-
subject.params do
|
428
|
-
requires :ary, type: Array do
|
429
|
-
requires :has_value, type: Grape::API::Boolean
|
430
|
-
given has_value: ->(has_value) { has_value } do
|
431
|
-
optional :type, type: String, values: %w[str int], default: 'str'
|
432
|
-
given type: ->(type) { type == 'str' } do
|
433
|
-
optional :str, type: String, default: 'a'
|
434
|
-
end
|
435
|
-
given type: ->(type) { type == 'int' } do
|
436
|
-
optional :int, type: Integer, default: 1
|
437
|
-
end
|
438
|
-
end
|
439
|
-
end
|
440
|
-
end
|
441
|
-
subject.post('/nested_given_and_default') { declared(self.params) }
|
442
|
-
|
443
|
-
params = {
|
444
|
-
ary: [
|
445
|
-
{ has_value: false },
|
446
|
-
{ has_value: true, type: 'int', int: 123 },
|
447
|
-
{ has_value: true, type: 'str', str: 'b' }
|
448
|
-
]
|
449
|
-
}
|
450
|
-
expected = {
|
451
|
-
'ary' => [
|
452
|
-
{ 'has_value' => false, 'type' => nil, 'int' => nil, 'str' => nil },
|
453
|
-
{ 'has_value' => true, 'type' => 'int', 'int' => 123, 'str' => nil },
|
454
|
-
{ 'has_value' => true, 'type' => 'str', 'int' => nil, 'str' => 'b' }
|
455
|
-
]
|
456
|
-
}
|
457
|
-
|
458
|
-
post '/nested_given_and_default', params
|
459
|
-
expect(last_response.status).to eq(201)
|
460
|
-
expect(JSON.parse(last_response.body)).to eq(expected)
|
461
|
-
end
|
462
|
-
end
|
463
|
-
end
|
@@ -1,233 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Validations::Validators::ExactlyOneOfValidator do
|
4
|
-
let_it_be(:app) do
|
5
|
-
Class.new(Grape::API) do
|
6
|
-
rescue_from Grape::Exceptions::ValidationErrors do |e|
|
7
|
-
error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
|
8
|
-
end
|
9
|
-
|
10
|
-
params do
|
11
|
-
optional :beer
|
12
|
-
optional :wine
|
13
|
-
optional :grapefruit
|
14
|
-
exactly_one_of :beer, :wine, :grapefruit
|
15
|
-
end
|
16
|
-
post do
|
17
|
-
end
|
18
|
-
|
19
|
-
params do
|
20
|
-
optional :beer
|
21
|
-
optional :wine
|
22
|
-
optional :grapefruit
|
23
|
-
optional :other
|
24
|
-
exactly_one_of :beer, :wine, :grapefruit
|
25
|
-
end
|
26
|
-
post 'mixed-params' do
|
27
|
-
end
|
28
|
-
|
29
|
-
params do
|
30
|
-
optional :beer
|
31
|
-
optional :wine
|
32
|
-
optional :grapefruit
|
33
|
-
exactly_one_of :beer, :wine, :grapefruit, message: 'you should choose one'
|
34
|
-
end
|
35
|
-
post '/custom-message' do
|
36
|
-
end
|
37
|
-
|
38
|
-
params do
|
39
|
-
requires :item, type: Hash do
|
40
|
-
optional :beer
|
41
|
-
optional :wine
|
42
|
-
optional :grapefruit
|
43
|
-
exactly_one_of :beer, :wine, :grapefruit
|
44
|
-
end
|
45
|
-
end
|
46
|
-
post '/nested-hash' do
|
47
|
-
end
|
48
|
-
|
49
|
-
params do
|
50
|
-
optional :item, type: Hash do
|
51
|
-
optional :beer
|
52
|
-
optional :wine
|
53
|
-
optional :grapefruit
|
54
|
-
exactly_one_of :beer, :wine, :grapefruit
|
55
|
-
end
|
56
|
-
end
|
57
|
-
post '/nested-optional-hash' do
|
58
|
-
end
|
59
|
-
|
60
|
-
params do
|
61
|
-
requires :items, type: Array do
|
62
|
-
optional :beer
|
63
|
-
optional :wine
|
64
|
-
optional :grapefruit
|
65
|
-
exactly_one_of :beer, :wine, :grapefruit
|
66
|
-
end
|
67
|
-
end
|
68
|
-
post '/nested-array' do
|
69
|
-
end
|
70
|
-
|
71
|
-
params do
|
72
|
-
requires :items, type: Array do
|
73
|
-
requires :nested_items, type: Array do
|
74
|
-
optional :beer, :wine, :grapefruit, type: Grape::API::Boolean
|
75
|
-
exactly_one_of :beer, :wine, :grapefruit
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
post '/deeply-nested-array' do
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
describe '#validate!' do
|
85
|
-
subject(:validate) { post path, params }
|
86
|
-
|
87
|
-
context 'when all params are present' do
|
88
|
-
let(:path) { '/' }
|
89
|
-
let(:params) { { beer: true, wine: true, grapefruit: true } }
|
90
|
-
|
91
|
-
it 'returns a validation error' do
|
92
|
-
validate
|
93
|
-
expect(last_response.status).to eq 400
|
94
|
-
expect(JSON.parse(last_response.body)).to eq(
|
95
|
-
'beer,wine,grapefruit' => ['are mutually exclusive']
|
96
|
-
)
|
97
|
-
end
|
98
|
-
|
99
|
-
context 'mixed with other params' do
|
100
|
-
let(:path) { '/mixed-params' }
|
101
|
-
let(:params) { { beer: true, wine: true, grapefruit: true, other: true } }
|
102
|
-
|
103
|
-
it 'returns a validation error' do
|
104
|
-
validate
|
105
|
-
expect(last_response.status).to eq 400
|
106
|
-
expect(JSON.parse(last_response.body)).to eq(
|
107
|
-
'beer,wine,grapefruit' => ['are mutually exclusive']
|
108
|
-
)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context 'when a subset of params are present' do
|
114
|
-
let(:path) { '/' }
|
115
|
-
let(:params) { { beer: true, grapefruit: true } }
|
116
|
-
|
117
|
-
it 'returns a validation error' do
|
118
|
-
validate
|
119
|
-
expect(last_response.status).to eq 400
|
120
|
-
expect(JSON.parse(last_response.body)).to eq(
|
121
|
-
'beer,grapefruit' => ['are mutually exclusive']
|
122
|
-
)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context 'when custom message is specified' do
|
127
|
-
let(:path) { '/custom-message' }
|
128
|
-
let(:params) { { beer: true, wine: true } }
|
129
|
-
|
130
|
-
it 'returns a validation error' do
|
131
|
-
validate
|
132
|
-
expect(last_response.status).to eq 400
|
133
|
-
expect(JSON.parse(last_response.body)).to eq(
|
134
|
-
'beer,wine' => ['you should choose one']
|
135
|
-
)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
context 'when exacly one param is present' do
|
140
|
-
let(:path) { '/' }
|
141
|
-
let(:params) { { beer: true, somethingelse: true } }
|
142
|
-
|
143
|
-
it 'does not return a validation error' do
|
144
|
-
validate
|
145
|
-
expect(last_response.status).to eq 201
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
context 'when none of the params are present' do
|
150
|
-
let(:path) { '/' }
|
151
|
-
let(:params) { { somethingelse: true } }
|
152
|
-
|
153
|
-
it 'returns a validation error' do
|
154
|
-
validate
|
155
|
-
expect(last_response.status).to eq 400
|
156
|
-
expect(JSON.parse(last_response.body)).to eq(
|
157
|
-
'beer,wine,grapefruit' => ['are missing, exactly one parameter must be provided']
|
158
|
-
)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context 'when params are nested inside required hash' do
|
163
|
-
let(:path) { '/nested-hash' }
|
164
|
-
let(:params) { { item: { beer: true, wine: true } } }
|
165
|
-
|
166
|
-
it 'returns a validation error with full names of the params' do
|
167
|
-
validate
|
168
|
-
expect(last_response.status).to eq 400
|
169
|
-
expect(JSON.parse(last_response.body)).to eq(
|
170
|
-
'item[beer],item[wine]' => ['are mutually exclusive']
|
171
|
-
)
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
context 'when params are nested inside optional hash' do
|
176
|
-
let(:path) { '/nested-optional-hash' }
|
177
|
-
|
178
|
-
context 'when params are passed' do
|
179
|
-
let(:params) { { item: { beer: true, wine: true } } }
|
180
|
-
|
181
|
-
it 'returns a validation error with full names of the params' do
|
182
|
-
validate
|
183
|
-
expect(last_response.status).to eq 400
|
184
|
-
expect(JSON.parse(last_response.body)).to eq(
|
185
|
-
'item[beer],item[wine]' => ['are mutually exclusive']
|
186
|
-
)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
context 'when params are empty' do
|
191
|
-
let(:params) { { other: true } }
|
192
|
-
|
193
|
-
it 'does not return a validation error' do
|
194
|
-
validate
|
195
|
-
expect(last_response.status).to eq 201
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
context 'when params are nested inside array' do
|
201
|
-
let(:path) { '/nested-array' }
|
202
|
-
let(:params) { { items: [{ beer: true, wine: true }, { wine: true, grapefruit: true }] } }
|
203
|
-
|
204
|
-
it 'returns a validation error with full names of the params' do
|
205
|
-
validate
|
206
|
-
expect(last_response.status).to eq 400
|
207
|
-
expect(JSON.parse(last_response.body)).to eq(
|
208
|
-
'items[0][beer],items[0][wine]' => [
|
209
|
-
'are mutually exclusive'
|
210
|
-
],
|
211
|
-
'items[1][wine],items[1][grapefruit]' => [
|
212
|
-
'are mutually exclusive'
|
213
|
-
]
|
214
|
-
)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
context 'when params are deeply nested' do
|
219
|
-
let(:path) { '/deeply-nested-array' }
|
220
|
-
let(:params) { { items: [{ nested_items: [{ beer: true, wine: true }] }] } }
|
221
|
-
|
222
|
-
it 'returns a validation error with full names of the params' do
|
223
|
-
validate
|
224
|
-
expect(last_response.status).to eq 400
|
225
|
-
expect(JSON.parse(last_response.body)).to eq(
|
226
|
-
'items[0][nested_items][0][beer],items[0][nested_items][0][wine]' => [
|
227
|
-
'are mutually exclusive'
|
228
|
-
]
|
229
|
-
)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|