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.
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,733 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Validators::ValuesValidator do
4
- let_it_be(:values_model) do
5
- Class.new do
6
- DEFAULT_VALUES = %w[valid-type1 valid-type2 valid-type3].freeze
7
- DEFAULT_EXCEPTS = %w[invalid-type1 invalid-type2 invalid-type3].freeze
8
-
9
- class << self
10
- def values
11
- @values ||= []
12
- [DEFAULT_VALUES + @values].flatten.uniq
13
- end
14
-
15
- def add_value(value)
16
- @values ||= []
17
- @values << value
18
- end
19
-
20
- def excepts
21
- @excepts ||= []
22
- [DEFAULT_EXCEPTS + @excepts].flatten.uniq
23
- end
24
-
25
- def add_except(except)
26
- @excepts ||= []
27
- @excepts << except
28
- end
29
-
30
- def include?(value)
31
- values.include?(value)
32
- end
33
-
34
- def even?(value)
35
- value.to_i.even?
36
- end
37
- end
38
- end
39
- end
40
-
41
- before do
42
- stub_const('ValuesModel', values_model)
43
- end
44
-
45
- let_it_be(:app) do
46
- ValuesModel = values_model
47
- Class.new(Grape::API) do
48
- default_format :json
49
-
50
- resources :custom_message do
51
- params do
52
- requires :type, values: { value: ValuesModel.values, message: 'value does not include in values' }
53
- end
54
- get '/' do
55
- { type: params[:type] }
56
- end
57
-
58
- params do
59
- optional :type, values: { value: -> { ValuesModel.values }, message: 'value does not include in values' }, default: 'valid-type2'
60
- end
61
- get '/lambda' do
62
- { type: params[:type] }
63
- end
64
-
65
- params do
66
- requires :type, values: { except: ValuesModel.excepts, except_message: 'value is on exclusions list', message: 'default exclude message' }
67
- end
68
- get '/exclude/exclude_message'
69
-
70
- params do
71
- requires :type, values: { except: -> { ValuesModel.excepts }, except_message: 'value is on exclusions list' }
72
- end
73
- get '/exclude/lambda/exclude_message'
74
-
75
- params do
76
- requires :type, values: { except: ValuesModel.excepts, message: 'default exclude message' }
77
- end
78
- get '/exclude/fallback_message'
79
- end
80
-
81
- params do
82
- requires :type, values: ValuesModel.values
83
- end
84
- get '/' do
85
- { type: params[:type] }
86
- end
87
-
88
- params do
89
- requires :type, values: []
90
- end
91
- get '/empty'
92
-
93
- params do
94
- optional :type, values: { value: ValuesModel.values }, default: 'valid-type2'
95
- end
96
- get '/default/hash/valid' do
97
- { type: params[:type] }
98
- end
99
-
100
- params do
101
- optional :type, values: ValuesModel.values, default: 'valid-type2'
102
- end
103
- get '/default/valid' do
104
- { type: params[:type] }
105
- end
106
-
107
- params do
108
- optional :type, values: { except: ValuesModel.excepts }, default: 'valid-type2'
109
- end
110
- get '/default/except' do
111
- { type: params[:type] }
112
- end
113
-
114
- params do
115
- optional :type, values: -> { ValuesModel.values }, default: 'valid-type2'
116
- end
117
- get '/lambda' do
118
- { type: params[:type] }
119
- end
120
-
121
- params do
122
- optional :type, type: Integer, values: 1..
123
- end
124
- get '/endless' do
125
- { type: params[:type] }
126
- end
127
-
128
- params do
129
- requires :type, values: ->(v) { ValuesModel.include? v }
130
- end
131
- get '/lambda_val' do
132
- { type: params[:type] }
133
- end
134
-
135
- params do
136
- requires :number, type: Integer, values: ->(v) { v > 0 }
137
- end
138
- get '/lambda_int_val' do
139
- { number: params[:number] }
140
- end
141
-
142
- params do
143
- requires :type, values: -> { [] }
144
- end
145
- get '/empty_lambda'
146
-
147
- params do
148
- optional :type, values: ValuesModel.values, default: -> { ValuesModel.values.sample }
149
- end
150
- get '/default_lambda' do
151
- { type: params[:type] }
152
- end
153
-
154
- params do
155
- optional :type, values: -> { ValuesModel.values }, default: -> { ValuesModel.values.sample }
156
- end
157
- get '/default_and_values_lambda' do
158
- { type: params[:type] }
159
- end
160
-
161
- params do
162
- optional :type, type: Grape::API::Boolean, desc: 'A boolean', values: [true]
163
- end
164
- get '/values/optional_boolean' do
165
- { type: params[:type] }
166
- end
167
-
168
- params do
169
- requires :type, type: Integer, desc: 'An integer', values: [10, 11], default: 10
170
- end
171
- get '/values/coercion' do
172
- { type: params[:type] }
173
- end
174
-
175
- params do
176
- requires :type, type: Array[Integer], desc: 'An integer', values: [10, 11], default: 10
177
- end
178
- get '/values/array_coercion' do
179
- { type: params[:type] }
180
- end
181
-
182
- params do
183
- optional :optional, type: Array do
184
- requires :type, values: %w[a b]
185
- end
186
- end
187
- get '/optional_with_required_values'
188
-
189
- params do
190
- requires :type, values: { except: ValuesModel.excepts }
191
- end
192
- get '/except/exclusive' do
193
- { type: params[:type] }
194
- end
195
-
196
- params do
197
- requires :type, type: String, values: { except: ValuesModel.excepts }
198
- end
199
- get '/except/exclusive/type' do
200
- { type: params[:type] }
201
- end
202
-
203
- params do
204
- requires :type, values: { except: -> { ValuesModel.excepts } }
205
- end
206
- get '/except/exclusive/lambda' do
207
- { type: params[:type] }
208
- end
209
-
210
- params do
211
- requires :type, type: String, values: { except: -> { ValuesModel.excepts } }
212
- end
213
- get '/except/exclusive/lambda/type' do
214
- { type: params[:type] }
215
- end
216
-
217
- params do
218
- requires :type, type: Integer, values: { except: -> { [3, 4, 5] } }
219
- end
220
- get '/except/exclusive/lambda/coercion' do
221
- { type: params[:type] }
222
- end
223
-
224
- params do
225
- requires :type, type: Integer, values: { value: 1..5, except: [3] }
226
- end
227
- get '/mixed/value/except' do
228
- { type: params[:type] }
229
- end
230
-
231
- params do
232
- optional :optional, type: Array[String], values: %w[a b c]
233
- end
234
- put '/optional_with_array_of_string_values'
235
-
236
- params do
237
- requires :type, values: { proc: ->(v) { ValuesModel.include? v } }
238
- end
239
- get '/proc' do
240
- { type: params[:type] }
241
- end
242
-
243
- params do
244
- requires :type, values: { proc: ->(v) { ValuesModel.include? v }, message: 'failed check' }
245
- end
246
- get '/proc/message'
247
-
248
- params do
249
- requires :number, values: { value: ->(v) { ValuesModel.even? v }, message: 'must be even' }
250
- end
251
- get '/proc/custom_message' do
252
- { message: 'success' }
253
- end
254
-
255
- params do
256
- requires :input_one, :input_two, values: { value: ->(v1, v2) { v1 + v2 > 10 } }
257
- end
258
- get '/proc/arity2'
259
-
260
- params do
261
- optional :name, type: String, values: %w[a b], allow_blank: true
262
- end
263
- get '/allow_blank'
264
- end
265
- end
266
-
267
- context 'with a custom validation message' do
268
- it 'allows a valid value for a parameter' do
269
- get('/custom_message', type: 'valid-type1')
270
- expect(last_response.status).to eq 200
271
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
272
- end
273
-
274
- it 'does not allow an invalid value for a parameter' do
275
- get('/custom_message', type: 'invalid-type')
276
- expect(last_response.status).to eq 400
277
- expect(last_response.body).to eq({ error: 'type value does not include in values' }.to_json)
278
- end
279
-
280
- it 'validates against values in a proc' do
281
- ValuesModel.add_value('valid-type4')
282
-
283
- get('/custom_message/lambda', type: 'valid-type4')
284
- expect(last_response.status).to eq 200
285
- expect(last_response.body).to eq({ type: 'valid-type4' }.to_json)
286
- end
287
-
288
- it 'does not allow an invalid value for a parameter using lambda' do
289
- get('/custom_message/lambda', type: 'invalid-type')
290
- expect(last_response.status).to eq 400
291
- expect(last_response.body).to eq({ error: 'type value does not include in values' }.to_json)
292
- end
293
- end
294
-
295
- context 'with a custom exclude validation message' do
296
- it 'does not allow an invalid value for a parameter' do
297
- get('/custom_message/exclude/exclude_message', type: 'invalid-type1')
298
- expect(last_response.status).to eq 400
299
- expect(last_response.body).to eq({ error: 'type value is on exclusions list' }.to_json)
300
- end
301
- end
302
-
303
- context 'with a custom exclude validation message' do
304
- it 'does not allow an invalid value for a parameter' do
305
- get('/custom_message/exclude/lambda/exclude_message', type: 'invalid-type1')
306
- expect(last_response.status).to eq 400
307
- expect(last_response.body).to eq({ error: 'type value is on exclusions list' }.to_json)
308
- end
309
- end
310
-
311
- context 'exclude with a standard custom validation message' do
312
- it 'does not allow an invalid value for a parameter' do
313
- get('/custom_message/exclude/fallback_message', type: 'invalid-type1')
314
- expect(last_response.status).to eq 400
315
- expect(last_response.body).to eq({ error: 'type default exclude message' }.to_json)
316
- end
317
- end
318
-
319
- it 'allows a valid value for a parameter' do
320
- get('/', type: 'valid-type1')
321
- expect(last_response.status).to eq 200
322
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
323
- end
324
-
325
- it 'does not allow an invalid value for a parameter' do
326
- get('/', type: 'invalid-type')
327
- expect(last_response.status).to eq 400
328
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
329
- end
330
-
331
- it 'rejects all values if values is an empty array' do
332
- get('/empty', type: 'invalid-type')
333
- expect(last_response.status).to eq 400
334
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
335
- end
336
-
337
- context 'nil value for a parameter' do
338
- it 'does not allow for root params scope' do
339
- get('/', type: nil)
340
- expect(last_response.status).to eq 400
341
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
342
- end
343
-
344
- it 'allows for a required param in child scope' do
345
- get('/optional_with_required_values')
346
- expect(last_response.status).to eq 200
347
- end
348
-
349
- it 'accepts for an optional param with a list of values' do
350
- put('/optional_with_array_of_string_values', optional: nil)
351
- expect(last_response.status).to eq 200
352
- end
353
- end
354
-
355
- it 'allows a valid default value' do
356
- get('/default/valid')
357
- expect(last_response.status).to eq 200
358
- expect(last_response.body).to eq({ type: 'valid-type2' }.to_json)
359
- end
360
-
361
- it 'allows a default value with except' do
362
- get('/default/except')
363
- expect(last_response.status).to eq 200
364
- expect(last_response.body).to eq({ type: 'valid-type2' }.to_json)
365
- end
366
-
367
- it 'allows a valid default value' do
368
- get('/default/hash/valid')
369
- expect(last_response.status).to eq 200
370
- expect(last_response.body).to eq({ type: 'valid-type2' }.to_json)
371
- end
372
-
373
- it 'allows a proc for values' do
374
- get('/lambda', type: 'valid-type1')
375
- expect(last_response.status).to eq 200
376
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
377
- end
378
-
379
- it 'does not validate updated values without proc' do
380
- ValuesModel.add_value('valid-type4')
381
- get('/', type: 'valid-type4')
382
- expect(last_response.status).to eq 400
383
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
384
- end
385
-
386
- it 'validates against values in a proc' do
387
- ValuesModel.add_value('valid-type4')
388
-
389
- get('/lambda', type: 'valid-type4')
390
- expect(last_response.status).to eq 200
391
- expect(last_response.body).to eq({ type: 'valid-type4' }.to_json)
392
- end
393
-
394
- it 'does not allow an invalid value for a parameter using lambda' do
395
- get('/lambda', type: 'invalid-type')
396
- expect(last_response.status).to eq 400
397
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
398
- end
399
-
400
- it 'validates against values in an endless range', if: ActiveSupport::VERSION::MAJOR >= 6 do
401
- get('/endless', type: 10)
402
- expect(last_response.status).to eq 200
403
- expect(last_response.body).to eq({ type: 10 }.to_json)
404
- end
405
-
406
- it 'does not allow an invalid value for a parameter using an endless range', if: ActiveSupport::VERSION::MAJOR >= 6 do
407
- get('/endless', type: 0)
408
- expect(last_response.status).to eq 400
409
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
410
- end
411
-
412
- it 'does not allow non-numeric string value for int value using lambda' do
413
- get('/lambda_int_val', number: 'foo')
414
- expect(last_response.status).to eq 400
415
- expect(last_response.body).to eq({ error: 'number is invalid, number does not have a valid value' }.to_json)
416
- end
417
-
418
- it 'does not allow nil for int value using lambda' do
419
- get('/lambda_int_val', number: nil)
420
- expect(last_response.status).to eq 400
421
- expect(last_response.body).to eq({ error: 'number does not have a valid value' }.to_json)
422
- end
423
-
424
- it 'allows numeric string for int value using lambda' do
425
- get('/lambda_int_val', number: '3')
426
- expect(last_response.status).to eq 200
427
- expect(last_response.body).to eq({ number: 3 }.to_json)
428
- end
429
-
430
- it 'allows value using lambda' do
431
- get('/lambda_val', type: 'valid-type1')
432
- expect(last_response.status).to eq 200
433
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
434
- end
435
-
436
- it 'does not allow invalid value using lambda' do
437
- get('/lambda_val', type: 'invalid-type')
438
- expect(last_response.status).to eq 400
439
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
440
- end
441
-
442
- it 'validates against an empty array in a proc' do
443
- get('/empty_lambda', type: 'any')
444
- expect(last_response.status).to eq 400
445
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
446
- end
447
-
448
- it 'validates default value from proc' do
449
- get('/default_lambda')
450
- expect(last_response.status).to eq 200
451
- end
452
-
453
- it 'validates default value from proc against values in a proc' do
454
- get('/default_and_values_lambda')
455
- expect(last_response.status).to eq 200
456
- end
457
-
458
- it 'raises IncompatibleOptionValues on an invalid default value from proc' do
459
- subject = Class.new(Grape::API)
460
- expect do
461
- subject.params { optional :type, values: %w[valid-type1 valid-type2 valid-type3], default: "#{ValuesModel.values.sample}_invalid" }
462
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
463
- end
464
-
465
- it 'raises IncompatibleOptionValues on an invalid default value' do
466
- subject = Class.new(Grape::API)
467
- expect do
468
- subject.params { optional :type, values: %w[valid-type1 valid-type2 valid-type3], default: 'invalid-type' }
469
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
470
- end
471
-
472
- it 'raises IncompatibleOptionValues when type is incompatible with values array' do
473
- subject = Class.new(Grape::API)
474
- expect do
475
- subject.params { optional :type, values: %w[valid-type1 valid-type2 valid-type3], type: Symbol }
476
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
477
- end
478
-
479
- context 'boolean values' do
480
- it 'allows a value from the list' do
481
- get('/values/optional_boolean', type: true)
482
-
483
- expect(last_response.status).to eq 200
484
- expect(last_response.body).to eq({ type: true }.to_json)
485
- end
486
-
487
- it 'rejects a value which is not in the list' do
488
- get('/values/optional_boolean', type: false)
489
-
490
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
491
- end
492
- end
493
-
494
- it 'allows values to be a kind of the coerced type not just an instance of it' do
495
- get('/values/coercion', type: 10)
496
- expect(last_response.status).to eq 200
497
- expect(last_response.body).to eq({ type: 10 }.to_json)
498
- end
499
-
500
- it 'allows values to be a kind of the coerced type in an array' do
501
- get('/values/array_coercion', type: [10])
502
- expect(last_response.status).to eq 200
503
- expect(last_response.body).to eq({ type: [10] }.to_json)
504
- end
505
-
506
- it 'raises IncompatibleOptionValues when values contains a value that is not a kind of the type' do
507
- subject = Class.new(Grape::API)
508
- expect do
509
- subject.params { requires :type, values: [10.5, 11], type: Integer }
510
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
511
- end
512
-
513
- it 'raises IncompatibleOptionValues when except contains a value that is not a kind of the type' do
514
- subject = Class.new(Grape::API)
515
- expect do
516
- subject.params { requires :type, values: { except: [10.5, 11] }, type: Integer }
517
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
518
- end
519
-
520
- it 'allows a blank value when the allow_blank option is true' do
521
- get 'allow_blank', name: nil
522
- expect(last_response.status).to eq(200)
523
-
524
- get 'allow_blank', name: ''
525
- expect(last_response.status).to eq(200)
526
- end
527
-
528
- context 'with a lambda values' do
529
- subject do
530
- Class.new(Grape::API) do
531
- params do
532
- optional :type, type: String, values: -> { [SecureRandom.uuid] }, default: -> { SecureRandom.uuid }
533
- end
534
- get '/random_values'
535
- end
536
- end
537
-
538
- def app
539
- subject
540
- end
541
-
542
- before do
543
- expect(SecureRandom).to receive(:uuid).and_return('foo').once
544
- end
545
-
546
- it 'only evaluates values dynamically with each request' do
547
- get '/random_values', type: 'foo'
548
- expect(last_response.status).to eq 200
549
- end
550
-
551
- it 'chooses default' do
552
- get '/random_values'
553
- expect(last_response.status).to eq 200
554
- end
555
- end
556
-
557
- context 'with a range of values' do
558
- subject(:app) do
559
- Class.new(Grape::API) do
560
- params do
561
- optional :value, type: Float, values: 0.0..10.0
562
- end
563
- get '/value' do
564
- { value: params[:value] }.to_json
565
- end
566
-
567
- params do
568
- optional :values, type: Array[Float], values: 0.0..10.0
569
- end
570
- get '/values' do
571
- { values: params[:values] }.to_json
572
- end
573
- end
574
- end
575
-
576
- it 'allows a single value inside of the range' do
577
- get('/value', value: 5.2)
578
- expect(last_response.status).to eq 200
579
- expect(last_response.body).to eq({ value: 5.2 }.to_json)
580
- end
581
-
582
- it 'allows an array of values inside of the range' do
583
- get('/values', values: [8.6, 7.5, 3, 0.9])
584
- expect(last_response.status).to eq 200
585
- expect(last_response.body).to eq({ values: [8.6, 7.5, 3.0, 0.9] }.to_json)
586
- end
587
-
588
- it 'rejects a single value outside the range' do
589
- get('/value', value: 'a')
590
- expect(last_response.status).to eq 400
591
- expect(last_response.body).to eq('value is invalid, value does not have a valid value')
592
- end
593
-
594
- it 'rejects an array of values if any of them are outside the range' do
595
- get('/values', values: [8.6, 75, 3, 0.9])
596
- expect(last_response.status).to eq 400
597
- expect(last_response.body).to eq('values does not have a valid value')
598
- end
599
- end
600
-
601
- context 'exclusive excepts' do
602
- it 'allows any other value outside excepts' do
603
- get '/except/exclusive', type: 'value'
604
- expect(last_response.status).to eq 200
605
- expect(last_response.body).to eq({ type: 'value' }.to_json)
606
- end
607
-
608
- it 'allows any other value outside excepts when type is included' do
609
- get '/except/exclusive/type', type: 'value'
610
- expect(last_response.status).to eq 200
611
- expect(last_response.body).to eq({ type: 'value' }.to_json)
612
- end
613
-
614
- it 'rejects values that matches except' do
615
- get '/except/exclusive', type: 'invalid-type1'
616
- expect(last_response.status).to eq 400
617
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
618
- end
619
-
620
- it 'rejects an array of values if any of them matches except' do
621
- get '/except/exclusive', type: %w[valid1 valid2 invalid-type1 valid4]
622
- expect(last_response.status).to eq 400
623
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
624
- end
625
- end
626
-
627
- context 'exclusive excepts with lambda' do
628
- it 'allows any other value outside excepts when type is included' do
629
- get '/except/exclusive/lambda/type', type: 'value'
630
- expect(last_response.status).to eq 200
631
- expect(last_response.body).to eq({ type: 'value' }.to_json)
632
- end
633
-
634
- it 'allows any other value outside excepts' do
635
- get '/except/exclusive/lambda', type: 'value'
636
- expect(last_response.status).to eq 200
637
- expect(last_response.body).to eq({ type: 'value' }.to_json)
638
- end
639
-
640
- it 'rejects values that matches except' do
641
- get '/except/exclusive/lambda', type: 'invalid-type1'
642
- expect(last_response.status).to eq 400
643
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
644
- end
645
- end
646
-
647
- context 'exclusive excepts with lambda and coercion' do
648
- it 'allows any other value outside excepts' do
649
- get '/except/exclusive/lambda/coercion', type: '10010000'
650
- expect(last_response.status).to eq 200
651
- expect(last_response.body).to eq({ type: 10_010_000 }.to_json)
652
- end
653
-
654
- it 'rejects values that matches except' do
655
- get '/except/exclusive/lambda/coercion', type: '3'
656
- expect(last_response.status).to eq 400
657
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
658
- end
659
- end
660
-
661
- context 'with mixed values and excepts' do
662
- it 'allows value, but not in except' do
663
- get '/mixed/value/except', type: 2
664
- expect(last_response.status).to eq 200
665
- expect(last_response.body).to eq({ type: 2 }.to_json)
666
- end
667
-
668
- it 'rejects except' do
669
- get '/mixed/value/except', type: 3
670
- expect(last_response.status).to eq 400
671
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
672
- end
673
-
674
- it 'rejects outside except and outside value' do
675
- get '/mixed/value/except', type: 10
676
- expect(last_response.status).to eq 400
677
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
678
- end
679
- end
680
-
681
- context 'custom validation using proc' do
682
- it 'accepts a single valid value' do
683
- get '/proc', type: 'valid-type1'
684
- expect(last_response.status).to eq 200
685
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
686
- end
687
-
688
- it 'accepts multiple valid values' do
689
- get '/proc', type: %w[valid-type1 valid-type3]
690
- expect(last_response.status).to eq 200
691
- expect(last_response.body).to eq({ type: %w[valid-type1 valid-type3] }.to_json)
692
- end
693
-
694
- it 'rejects a single invalid value' do
695
- get '/proc', type: 'invalid-type1'
696
- expect(last_response.status).to eq 400
697
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
698
- end
699
-
700
- it 'rejects an invalid value among valid ones' do
701
- get '/proc', type: %w[valid-type1 invalid-type1 valid-type3]
702
- expect(last_response.status).to eq 400
703
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
704
- end
705
-
706
- it 'uses supplied message' do
707
- get '/proc/message', type: 'invalid-type1'
708
- expect(last_response.status).to eq 400
709
- expect(last_response.body).to eq({ error: 'type failed check' }.to_json)
710
- end
711
-
712
- context 'when proc has an arity of 1' do
713
- it 'accepts a valid value' do
714
- get '/proc/custom_message', number: 4
715
- expect(last_response.status).to eq 200
716
- expect(last_response.body).to eq({ message: 'success' }.to_json)
717
- end
718
-
719
- it 'rejects an invalid value' do
720
- get '/proc/custom_message', number: 5
721
- expect(last_response.status).to eq 400
722
- expect(last_response.body).to eq({ error: 'number must be even' }.to_json)
723
- end
724
- end
725
-
726
- context 'when arity is > 1' do
727
- it 'returns an error status code' do
728
- get '/proc/arity2', input_one: 2, input_two: 3
729
- expect(last_response.status).to eq 400
730
- end
731
- end
732
- end
733
- end