grape 1.7.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +30 -25
  5. data/UPGRADING.md +35 -0
  6. data/grape.gemspec +3 -6
  7. data/lib/grape/api.rb +2 -2
  8. data/lib/grape/content_types.rb +2 -8
  9. data/lib/grape/dsl/desc.rb +1 -1
  10. data/lib/grape/dsl/inside_route.rb +11 -11
  11. data/lib/grape/dsl/request_response.rb +2 -1
  12. data/lib/grape/dsl/settings.rb +2 -6
  13. data/lib/grape/endpoint.rb +28 -18
  14. data/lib/grape/error_formatter/base.rb +1 -1
  15. data/lib/grape/exceptions/base.rb +2 -2
  16. data/lib/grape/exceptions/missing_group_type.rb +1 -6
  17. data/lib/grape/exceptions/unsupported_group_type.rb +1 -6
  18. data/lib/grape/exceptions/validation_errors.rb +1 -6
  19. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +3 -3
  20. data/lib/grape/extensions/hash.rb +4 -7
  21. data/lib/grape/extensions/hashie/mash.rb +3 -3
  22. data/lib/grape/formatter/serializable_hash.rb +7 -7
  23. data/lib/grape/http/headers.rb +12 -2
  24. data/lib/grape/middleware/auth/base.rb +1 -1
  25. data/lib/grape/middleware/auth/strategies.rb +1 -2
  26. data/lib/grape/middleware/error.rb +5 -5
  27. data/lib/grape/middleware/formatter.rb +6 -6
  28. data/lib/grape/middleware/versioner/header.rb +11 -19
  29. data/lib/grape/railtie.rb +9 -0
  30. data/lib/grape/request.rb +8 -2
  31. data/lib/grape/router/route.rb +1 -3
  32. data/lib/grape/util/lazy_value.rb +3 -11
  33. data/lib/grape/util/strict_hash_configuration.rb +3 -4
  34. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  35. data/lib/grape/validations/params_scope.rb +8 -2
  36. data/lib/grape/validations/single_attribute_iterator.rb +3 -1
  37. data/lib/grape/validations/types/custom_type_coercer.rb +2 -16
  38. data/lib/grape/validations/validators/base.rb +9 -20
  39. data/lib/grape/validations/validators/default_validator.rb +2 -20
  40. data/lib/grape/validations/validators/multiple_params_base.rb +4 -8
  41. data/lib/grape/validations/validators/values_validator.rb +14 -5
  42. data/lib/grape/version.rb +1 -1
  43. data/lib/grape.rb +26 -5
  44. metadata +13 -253
  45. data/lib/grape/config.rb +0 -34
  46. data/lib/grape/extensions/deep_mergeable_hash.rb +0 -21
  47. data/lib/grape/extensions/deep_symbolize_hash.rb +0 -32
  48. data/spec/grape/api/custom_validations_spec.rb +0 -256
  49. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  50. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  51. data/spec/grape/api/documentation_spec.rb +0 -59
  52. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  53. data/spec/grape/api/instance_spec.rb +0 -103
  54. data/spec/grape/api/invalid_format_spec.rb +0 -45
  55. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  56. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  57. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  58. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  59. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  60. data/spec/grape/api/recognize_path_spec.rb +0 -21
  61. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  62. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  63. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  64. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  65. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  66. data/spec/grape/api_remount_spec.rb +0 -473
  67. data/spec/grape/api_spec.rb +0 -4347
  68. data/spec/grape/config_spec.rb +0 -17
  69. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  70. data/spec/grape/dsl/desc_spec.rb +0 -101
  71. data/spec/grape/dsl/headers_spec.rb +0 -62
  72. data/spec/grape/dsl/helpers_spec.rb +0 -100
  73. data/spec/grape/dsl/inside_route_spec.rb +0 -535
  74. data/spec/grape/dsl/logger_spec.rb +0 -24
  75. data/spec/grape/dsl/middleware_spec.rb +0 -60
  76. data/spec/grape/dsl/parameters_spec.rb +0 -180
  77. data/spec/grape/dsl/request_response_spec.rb +0 -206
  78. data/spec/grape/dsl/routing_spec.rb +0 -275
  79. data/spec/grape/dsl/settings_spec.rb +0 -261
  80. data/spec/grape/dsl/validations_spec.rb +0 -55
  81. data/spec/grape/endpoint/declared_spec.rb +0 -846
  82. data/spec/grape/endpoint_spec.rb +0 -1085
  83. data/spec/grape/entity_spec.rb +0 -336
  84. data/spec/grape/exceptions/base_spec.rb +0 -81
  85. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -145
  86. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  87. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  88. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  89. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  90. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -21
  91. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  92. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  93. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  94. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  95. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -23
  96. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  97. data/spec/grape/exceptions/validation_spec.rb +0 -19
  98. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  99. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  100. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  101. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  102. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  103. data/spec/grape/integration/rack_spec.rb +0 -51
  104. data/spec/grape/loading_spec.rb +0 -44
  105. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  106. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  107. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  108. data/spec/grape/middleware/base_spec.rb +0 -221
  109. data/spec/grape/middleware/error_spec.rb +0 -85
  110. data/spec/grape/middleware/exception_spec.rb +0 -294
  111. data/spec/grape/middleware/formatter_spec.rb +0 -461
  112. data/spec/grape/middleware/globals_spec.rb +0 -30
  113. data/spec/grape/middleware/stack_spec.rb +0 -155
  114. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  115. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  116. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  117. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  118. data/spec/grape/middleware/versioner_spec.rb +0 -21
  119. data/spec/grape/named_api_spec.rb +0 -19
  120. data/spec/grape/parser_spec.rb +0 -86
  121. data/spec/grape/path_spec.rb +0 -252
  122. data/spec/grape/presenters/presenter_spec.rb +0 -71
  123. data/spec/grape/request_spec.rb +0 -136
  124. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  125. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  126. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  127. data/spec/grape/util/stackable_values_spec.rb +0 -128
  128. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  129. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  130. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  131. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -40
  132. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  133. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -57
  134. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  135. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  136. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  137. data/spec/grape/validations/types_spec.rb +0 -111
  138. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  139. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  140. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  141. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  142. data/spec/grape/validations/validators/default_spec.rb +0 -463
  143. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  144. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  145. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  146. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  147. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  148. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  149. data/spec/grape/validations/validators/values_spec.rb +0 -696
  150. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  151. data/spec/grape/validations_spec.rb +0 -2029
  152. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  153. data/spec/integration/multi_json/json_spec.rb +0 -7
  154. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  155. data/spec/shared/versioning_examples.rb +0 -215
  156. data/spec/spec_helper.rb +0 -52
  157. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  158. data/spec/support/chunks.rb +0 -14
  159. data/spec/support/content_type_helpers.rb +0 -15
  160. data/spec/support/endpoint_faker.rb +0 -25
  161. data/spec/support/file_streamer.rb +0 -13
  162. data/spec/support/integer_helpers.rb +0 -13
  163. data/spec/support/versioned_helpers.rb +0 -55
@@ -1,192 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Validators::ExceptValuesValidator do
4
- module ValidationsSpec
5
- class ExceptValuesModel
6
- DEFAULT_EXCEPTS = %w[invalid-type1 invalid-type2 invalid-type3].freeze
7
- class << self
8
- attr_accessor :excepts
9
-
10
- def excepts
11
- @excepts ||= []
12
- [DEFAULT_EXCEPTS + @excepts].flatten.uniq
13
- end
14
- end
15
- end
16
-
17
- TEST_CASES = {
18
- req_except: {
19
- requires: { except_values: ExceptValuesModel.excepts },
20
- tests: [
21
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
22
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
23
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
24
- ]
25
- },
26
- req_except_hash: {
27
- requires: { except_values: { value: ExceptValuesModel.excepts } },
28
- tests: [
29
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
30
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
31
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
32
- ]
33
- },
34
- req_except_custom_message: {
35
- requires: { except_values: { value: ExceptValuesModel.excepts, message: 'is not allowed' } },
36
- tests: [
37
- { value: 'invalid-type1', rc: 400, body: { error: 'type is not allowed' }.to_json },
38
- { value: 'invalid-type3', rc: 400, body: { error: 'type is not allowed' }.to_json },
39
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
40
- ]
41
- },
42
- req_except_no_value: {
43
- requires: { except_values: { message: 'is not allowed' } },
44
- tests: [
45
- { value: 'invalid-type1', rc: 200, body: { type: 'invalid-type1' }.to_json }
46
- ]
47
- },
48
- req_except_empty: {
49
- requires: { except_values: [] },
50
- tests: [
51
- { value: 'invalid-type1', rc: 200, body: { type: 'invalid-type1' }.to_json }
52
- ]
53
- },
54
- req_except_lambda: {
55
- requires: { except_values: -> { ExceptValuesModel.excepts } },
56
- add_excepts: ['invalid-type4'],
57
- tests: [
58
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
59
- { value: 'invalid-type4', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
60
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
61
- ]
62
- },
63
- req_except_lambda_custom_message: {
64
- requires: { except_values: { value: -> { ExceptValuesModel.excepts }, message: 'is not allowed' } },
65
- add_excepts: ['invalid-type4'],
66
- tests: [
67
- { value: 'invalid-type1', rc: 400, body: { error: 'type is not allowed' }.to_json },
68
- { value: 'invalid-type4', rc: 400, body: { error: 'type is not allowed' }.to_json },
69
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
70
- ]
71
- },
72
- opt_except_default: {
73
- optional: { except_values: ExceptValuesModel.excepts, default: 'valid-type2' },
74
- tests: [
75
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
76
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
77
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json },
78
- { rc: 200, body: { type: 'valid-type2' }.to_json }
79
- ]
80
- },
81
- opt_except_lambda_default: {
82
- optional: { except_values: -> { ExceptValuesModel.excepts }, default: 'valid-type2' },
83
- tests: [
84
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
85
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
86
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json },
87
- { rc: 200, body: { type: 'valid-type2' }.to_json }
88
- ]
89
- },
90
- req_except_type_coerce: {
91
- requires: { type: Integer, except_values: [10, 11] },
92
- tests: [
93
- { value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
94
- { value: 11, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
95
- { value: '11', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
96
- { value: '3', rc: 200, body: { type: 3 }.to_json },
97
- { value: 3, rc: 200, body: { type: 3 }.to_json }
98
- ]
99
- },
100
- opt_except_type_coerce_default: {
101
- optional: { type: Integer, except_values: [10, 11], default: 12 },
102
- tests: [
103
- { value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
104
- { value: 10, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
105
- { value: '3', rc: 200, body: { type: 3 }.to_json },
106
- { value: 3, rc: 200, body: { type: 3 }.to_json },
107
- { rc: 200, body: { type: 12 }.to_json }
108
- ]
109
- },
110
- opt_except_array_type_coerce_default: {
111
- optional: { type: Array[Integer], except_values: [10, 11], default: 12 },
112
- tests: [
113
- { value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
114
- { value: 10, rc: 400, body: { error: 'type is invalid' }.to_json },
115
- { value: [10], rc: 400, body: { error: 'type has a value not allowed' }.to_json },
116
- { value: ['3'], rc: 200, body: { type: [3] }.to_json },
117
- { value: [3], rc: 200, body: { type: [3] }.to_json },
118
- { rc: 200, body: { type: 12 }.to_json }
119
- ]
120
- },
121
- req_except_range: {
122
- optional: { type: Integer, except_values: 10..12 },
123
- tests: [
124
- { value: 11, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
125
- { value: 13, rc: 200, body: { type: 13 }.to_json }
126
- ]
127
- }
128
- }.freeze
129
-
130
- module ExceptValidatorSpec
131
- class API < Grape::API
132
- default_format :json
133
-
134
- TEST_CASES.each_with_index do |(k, v), _i|
135
- params do
136
- requires :type, v[:requires] if v.key? :requires
137
- optional :type, v[:optional] if v.key? :optional
138
- end
139
- get k do
140
- { type: params[:type] }
141
- end
142
- end
143
- end
144
- end
145
- end
146
-
147
- it 'raises IncompatibleOptionValues on a default value in exclude' do
148
- subject = Class.new(Grape::API)
149
- expect do
150
- subject.params do
151
- optional :type, except_values: ValidationsSpec::ExceptValuesModel.excepts,
152
- default: ValidationsSpec::ExceptValuesModel.excepts.sample
153
- end
154
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
155
- end
156
-
157
- it 'raises IncompatibleOptionValues when a default array has excluded values' do
158
- subject = Class.new(Grape::API)
159
- expect do
160
- subject.params do
161
- optional :type, type: Array[Integer],
162
- except_values: 10..12,
163
- default: [8, 9, 10]
164
- end
165
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
166
- end
167
-
168
- it 'raises IncompatibleOptionValues when type is incompatible with values array' do
169
- subject = Class.new(Grape::API)
170
- expect do
171
- subject.params { optional :type, except_values: %w[valid-type1 valid-type2 valid-type3], type: Symbol }
172
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
173
- end
174
-
175
- def app
176
- ValidationsSpec::ExceptValidatorSpec::API
177
- end
178
-
179
- ValidationsSpec::TEST_CASES.each_with_index do |(k, v), i|
180
- v[:tests].each do |t|
181
- it "#{i}: #{k} - #{t[:value]}" do
182
- ValidationsSpec::ExceptValuesModel.excepts = v[:add_excepts] if v.key? :add_excepts
183
- body = {}
184
- body[:type] = t[:value] if t.key? :value
185
- get k.to_s, **body
186
- expect(last_response.status).to eq t[:rc]
187
- expect(last_response.body).to eq t[:body]
188
- ValidationsSpec::ExceptValuesModel.excepts = nil
189
- end
190
- end
191
- end
192
- end
@@ -1,214 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Validators::MutualExclusionValidator 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
- mutually_exclusive :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
- mutually_exclusive :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
- mutually_exclusive :beer, :wine, :grapefruit, message: 'you should not mix beer and wine'
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
- mutually_exclusive :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
- mutually_exclusive :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
- mutually_exclusive :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
- mutually_exclusive :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 mutually exclusive 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 mutually exclusive 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 not mix beer and wine']
135
- )
136
- end
137
- end
138
-
139
- context 'when no mutually exclusive params are 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 mutually exclusive params are nested inside required hash' do
150
- let(:path) { '/nested-hash' }
151
- let(:params) { { item: { beer: true, wine: true } } }
152
-
153
- it 'returns a validation error with full names of the params' do
154
- validate
155
- expect(last_response.status).to eq 400
156
- expect(JSON.parse(last_response.body)).to eq(
157
- 'item[beer],item[wine]' => ['are mutually exclusive']
158
- )
159
- end
160
- end
161
-
162
- context 'when mutually exclusive params are nested inside optional hash' do
163
- let(:path) { '/nested-optional-hash' }
164
-
165
- context 'when params are passed' do
166
- let(:params) { { item: { beer: true, wine: true } } }
167
-
168
- it 'returns a validation error with full names of the params' do
169
- validate
170
- expect(last_response.status).to eq 400
171
- expect(JSON.parse(last_response.body)).to eq(
172
- 'item[beer],item[wine]' => ['are mutually exclusive']
173
- )
174
- end
175
- end
176
-
177
- context 'when params are empty' do
178
- let(:params) { {} }
179
-
180
- it 'does not return a validation error' do
181
- validate
182
- expect(last_response.status).to eq 201
183
- end
184
- end
185
- end
186
-
187
- context 'when mutually exclusive params are nested inside array' do
188
- let(:path) { '/nested-array' }
189
- let(:params) { { items: [{ beer: true, wine: true }, { wine: true, grapefruit: true }] } }
190
-
191
- it 'returns a validation error with full names of the params' do
192
- validate
193
- expect(last_response.status).to eq 400
194
- expect(JSON.parse(last_response.body)).to eq(
195
- 'items[0][beer],items[0][wine]' => ['are mutually exclusive'],
196
- 'items[1][wine],items[1][grapefruit]' => ['are mutually exclusive']
197
- )
198
- end
199
- end
200
-
201
- context 'when mutually exclusive params are deeply nested' do
202
- let(:path) { '/deeply-nested-array' }
203
- let(:params) { { items: [{ nested_items: [{ beer: true, wine: true }] }] } }
204
-
205
- it 'returns a validation error with full names of the params' do
206
- validate
207
- expect(last_response.status).to eq 400
208
- expect(JSON.parse(last_response.body)).to eq(
209
- 'items[0][nested_items][0][beer],items[0][nested_items][0][wine]' => ['are mutually exclusive']
210
- )
211
- end
212
- end
213
- end
214
- end