grape 1.8.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +19 -22
  4. data/UPGRADING.md +35 -0
  5. data/grape.gemspec +1 -4
  6. data/lib/grape/dsl/desc.rb +1 -1
  7. data/lib/grape/dsl/inside_route.rb +9 -9
  8. data/lib/grape/endpoint.rb +9 -1
  9. data/lib/grape/exceptions/missing_group_type.rb +1 -1
  10. data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
  11. data/lib/grape/http/headers.rb +12 -2
  12. data/lib/grape/middleware/auth/strategies.rb +1 -2
  13. data/lib/grape/middleware/error.rb +4 -4
  14. data/lib/grape/middleware/formatter.rb +5 -5
  15. data/lib/grape/railtie.rb +9 -0
  16. data/lib/grape/request.rb +8 -2
  17. data/lib/grape/router/route.rb +1 -1
  18. data/lib/grape/validations/validators/base.rb +1 -1
  19. data/lib/grape/validations/validators/values_validator.rb +2 -2
  20. data/lib/grape/version.rb +1 -1
  21. data/lib/grape.rb +15 -2
  22. metadata +8 -243
  23. data/spec/grape/api/custom_validations_spec.rb +0 -213
  24. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  25. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  26. data/spec/grape/api/documentation_spec.rb +0 -59
  27. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  28. data/spec/grape/api/instance_spec.rb +0 -103
  29. data/spec/grape/api/invalid_format_spec.rb +0 -45
  30. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  31. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  32. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  33. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  34. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  35. data/spec/grape/api/recognize_path_spec.rb +0 -21
  36. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  37. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  38. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  39. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  40. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  41. data/spec/grape/api_remount_spec.rb +0 -509
  42. data/spec/grape/api_spec.rb +0 -4356
  43. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  44. data/spec/grape/dsl/desc_spec.rb +0 -98
  45. data/spec/grape/dsl/headers_spec.rb +0 -62
  46. data/spec/grape/dsl/helpers_spec.rb +0 -100
  47. data/spec/grape/dsl/inside_route_spec.rb +0 -531
  48. data/spec/grape/dsl/logger_spec.rb +0 -24
  49. data/spec/grape/dsl/middleware_spec.rb +0 -60
  50. data/spec/grape/dsl/parameters_spec.rb +0 -180
  51. data/spec/grape/dsl/request_response_spec.rb +0 -225
  52. data/spec/grape/dsl/routing_spec.rb +0 -275
  53. data/spec/grape/dsl/settings_spec.rb +0 -261
  54. data/spec/grape/dsl/validations_spec.rb +0 -55
  55. data/spec/grape/endpoint/declared_spec.rb +0 -846
  56. data/spec/grape/endpoint_spec.rb +0 -1085
  57. data/spec/grape/entity_spec.rb +0 -336
  58. data/spec/grape/exceptions/base_spec.rb +0 -81
  59. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
  60. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  61. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  62. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  63. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  64. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
  65. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  66. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  67. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  68. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  69. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
  70. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  71. data/spec/grape/exceptions/validation_spec.rb +0 -19
  72. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  73. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  74. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  75. data/spec/grape/grape_spec.rb +0 -9
  76. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  77. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  78. data/spec/grape/integration/rack_spec.rb +0 -51
  79. data/spec/grape/loading_spec.rb +0 -44
  80. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  81. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  82. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  83. data/spec/grape/middleware/base_spec.rb +0 -221
  84. data/spec/grape/middleware/error_spec.rb +0 -85
  85. data/spec/grape/middleware/exception_spec.rb +0 -294
  86. data/spec/grape/middleware/formatter_spec.rb +0 -461
  87. data/spec/grape/middleware/globals_spec.rb +0 -30
  88. data/spec/grape/middleware/stack_spec.rb +0 -155
  89. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  90. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  91. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  92. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  93. data/spec/grape/middleware/versioner_spec.rb +0 -21
  94. data/spec/grape/named_api_spec.rb +0 -19
  95. data/spec/grape/parser_spec.rb +0 -86
  96. data/spec/grape/path_spec.rb +0 -252
  97. data/spec/grape/presenters/presenter_spec.rb +0 -71
  98. data/spec/grape/request_spec.rb +0 -126
  99. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  100. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  101. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  102. data/spec/grape/util/stackable_values_spec.rb +0 -128
  103. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  104. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  105. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  106. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
  107. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  108. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
  109. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  110. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  111. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  112. data/spec/grape/validations/types_spec.rb +0 -111
  113. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  114. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  115. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  116. data/spec/grape/validations/validators/base_spec.rb +0 -38
  117. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  118. data/spec/grape/validations/validators/default_spec.rb +0 -463
  119. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  120. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  121. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  122. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  123. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  124. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  125. data/spec/grape/validations/validators/values_spec.rb +0 -733
  126. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  127. data/spec/grape/validations_spec.rb +0 -2030
  128. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  129. data/spec/integration/multi_json/json_spec.rb +0 -7
  130. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  131. data/spec/shared/deprecated_class_examples.rb +0 -16
  132. data/spec/shared/versioning_examples.rb +0 -215
  133. data/spec/spec_helper.rb +0 -52
  134. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  135. data/spec/support/chunks.rb +0 -14
  136. data/spec/support/content_type_helpers.rb +0 -15
  137. data/spec/support/endpoint_faker.rb +0 -25
  138. data/spec/support/file_streamer.rb +0 -13
  139. data/spec/support/integer_helpers.rb +0 -13
  140. 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