grape 1.2.4 → 1.2.5
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 +18 -4
- data/README.md +144 -4
- data/grape.gemspec +3 -1
- data/lib/grape.rb +94 -66
- data/lib/grape/api.rb +46 -4
- data/lib/grape/api/instance.rb +23 -12
- data/lib/grape/dsl/desc.rb +11 -2
- data/lib/grape/dsl/validations.rb +4 -3
- data/lib/grape/eager_load.rb +18 -0
- data/lib/grape/endpoint.rb +3 -3
- data/lib/grape/error_formatter.rb +1 -1
- data/lib/grape/exceptions/validation_errors.rb +4 -2
- data/lib/grape/formatter.rb +1 -1
- data/lib/grape/middleware/auth/base.rb +2 -4
- data/lib/grape/middleware/base.rb +2 -0
- data/lib/grape/middleware/helpers.rb +10 -0
- data/lib/grape/parser.rb +1 -1
- data/lib/grape/util/base_inheritable.rb +34 -0
- data/lib/grape/util/inheritable_values.rb +5 -25
- data/lib/grape/util/lazy_block.rb +25 -0
- data/lib/grape/util/lazy_value.rb +5 -0
- data/lib/grape/util/reverse_stackable_values.rb +7 -36
- data/lib/grape/util/stackable_values.rb +19 -22
- data/lib/grape/validations/attributes_iterator.rb +5 -3
- data/lib/grape/validations/multiple_attributes_iterator.rb +11 -0
- data/lib/grape/validations/params_scope.rb +12 -12
- data/lib/grape/validations/single_attribute_iterator.rb +13 -0
- data/lib/grape/validations/validator_factory.rb +6 -11
- data/lib/grape/validations/validators/all_or_none.rb +6 -13
- data/lib/grape/validations/validators/at_least_one_of.rb +5 -13
- data/lib/grape/validations/validators/base.rb +11 -10
- data/lib/grape/validations/validators/coerce.rb +4 -0
- data/lib/grape/validations/validators/default.rb +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +6 -23
- data/lib/grape/validations/validators/multiple_params_base.rb +14 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +6 -18
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/defines_boolean_in_params_spec.rb +37 -0
- data/spec/grape/api_remount_spec.rb +158 -0
- data/spec/grape/api_spec.rb +72 -0
- data/spec/grape/endpoint_spec.rb +1 -1
- data/spec/grape/exceptions/base_spec.rb +4 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +6 -4
- data/spec/grape/integration/rack_spec.rb +22 -6
- data/spec/grape/middleware/base_spec.rb +8 -0
- data/spec/grape/middleware/formatter_spec.rb +11 -1
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +29 -0
- data/spec/grape/validations/params_scope_spec.rb +13 -0
- data/spec/grape/validations/single_attribute_iterator_spec.rb +33 -0
- data/spec/grape/validations/validators/all_or_none_spec.rb +138 -30
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +173 -29
- data/spec/grape/validations/validators/coerce_spec.rb +6 -2
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +202 -38
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +184 -27
- data/spec/grape/validations_spec.rb +32 -20
- metadata +103 -115
- data/Appraisals +0 -28
- data/Dangerfile +0 -2
- data/Gemfile +0 -33
- data/Gemfile.lock +0 -231
- data/Guardfile +0 -10
- data/RELEASING.md +0 -111
- data/Rakefile +0 -25
- data/benchmark/simple.rb +0 -27
- data/benchmark/simple_with_type_coercer.rb +0 -22
- data/gemfiles/multi_json.gemfile +0 -35
- data/gemfiles/multi_xml.gemfile +0 -35
- data/gemfiles/rack_1.5.2.gemfile.lock +0 -232
- data/gemfiles/rack_edge.gemfile +0 -35
- data/gemfiles/rails_3.gemfile +0 -36
- data/gemfiles/rails_3.gemfile.lock +0 -288
- data/gemfiles/rails_4.gemfile +0 -35
- data/gemfiles/rails_4.gemfile.lock +0 -280
- data/gemfiles/rails_5.gemfile +0 -35
- data/gemfiles/rails_5.gemfile.lock +0 -312
- data/gemfiles/rails_edge.gemfile +0 -35
- data/pkg/grape-1.2.0.gem +0 -0
- data/pkg/grape-1.2.1.gem +0 -0
- data/pkg/grape-1.2.3.gem +0 -0
@@ -20,10 +20,13 @@ describe Grape::Validations::CoerceValidator do
|
|
20
20
|
|
21
21
|
context 'i18n' do
|
22
22
|
after :each do
|
23
|
+
I18n.available_locales = %i[en]
|
23
24
|
I18n.locale = :en
|
25
|
+
I18n.default_locale = :en
|
24
26
|
end
|
25
27
|
|
26
28
|
it 'i18n error on malformed input' do
|
29
|
+
I18n.available_locales = %i[en zh-CN]
|
27
30
|
I18n.load_path << File.expand_path('../zh-CN.yml', __FILE__)
|
28
31
|
I18n.reload!
|
29
32
|
I18n.locale = 'zh-CN'.to_sym
|
@@ -40,6 +43,7 @@ describe Grape::Validations::CoerceValidator do
|
|
40
43
|
end
|
41
44
|
|
42
45
|
it 'gives an english fallback error when default locale message is blank' do
|
46
|
+
I18n.available_locales = %i[en pt-BR]
|
43
47
|
I18n.locale = 'pt-BR'.to_sym
|
44
48
|
subject.params do
|
45
49
|
requires :age, type: Integer
|
@@ -576,7 +580,7 @@ describe Grape::Validations::CoerceValidator do
|
|
576
580
|
expect(last_response.status).to eq(200)
|
577
581
|
expect(last_response.body).to eq('arrays work')
|
578
582
|
|
579
|
-
get '/', splines: [{ x: 2, ints: [] }, { x: 3, ints: [4], obj: { y: 'quack' } }]
|
583
|
+
get '/', splines: [{ x: 2, ints: [5] }, { x: 3, ints: [4], obj: { y: 'quack' } }]
|
580
584
|
expect(last_response.status).to eq(200)
|
581
585
|
expect(last_response.body).to eq('arrays work')
|
582
586
|
|
@@ -592,7 +596,7 @@ describe Grape::Validations::CoerceValidator do
|
|
592
596
|
expect(last_response.status).to eq(400)
|
593
597
|
expect(last_response.body).to eq('splines[x] does not have a valid value')
|
594
598
|
|
595
|
-
get '/', splines: [{ x: 1, ints: [] }, { x: 4, ints: [] }]
|
599
|
+
get '/', splines: [{ x: 1, ints: [5] }, { x: 4, ints: [6] }]
|
596
600
|
expect(last_response.status).to eq(400)
|
597
601
|
expect(last_response.body).to eq('splines[x] does not have a valid value')
|
598
602
|
end
|
@@ -2,73 +2,237 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Grape::Validations::ExactlyOneOfValidator do
|
4
4
|
describe '#validate!' do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
subject(:validate) { post path, params }
|
6
|
+
|
7
|
+
module ValidationsSpec
|
8
|
+
module ExactlyOneOfValidatorSpec
|
9
|
+
class API < Grape::API
|
10
|
+
rescue_from Grape::Exceptions::ValidationErrors do |e|
|
11
|
+
error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
|
12
|
+
end
|
13
|
+
|
14
|
+
params do
|
15
|
+
optional :beer
|
16
|
+
optional :wine
|
17
|
+
optional :grapefruit
|
18
|
+
exactly_one_of :beer, :wine, :grapefruit
|
19
|
+
end
|
20
|
+
post do
|
21
|
+
end
|
22
|
+
|
23
|
+
params do
|
24
|
+
optional :beer
|
25
|
+
optional :wine
|
26
|
+
optional :grapefruit
|
27
|
+
optional :other
|
28
|
+
exactly_one_of :beer, :wine, :grapefruit
|
29
|
+
end
|
30
|
+
post 'mixed-params' do
|
31
|
+
end
|
32
|
+
|
33
|
+
params do
|
34
|
+
optional :beer
|
35
|
+
optional :wine
|
36
|
+
optional :grapefruit
|
37
|
+
exactly_one_of :beer, :wine, :grapefruit, message: 'you should choose one'
|
38
|
+
end
|
39
|
+
post '/custom-message' do
|
40
|
+
end
|
10
41
|
|
11
|
-
|
42
|
+
params do
|
43
|
+
requires :item, type: Hash do
|
44
|
+
optional :beer
|
45
|
+
optional :wine
|
46
|
+
optional :grapefruit
|
47
|
+
exactly_one_of :beer, :wine, :grapefruit
|
48
|
+
end
|
49
|
+
end
|
50
|
+
post '/nested-hash' do
|
51
|
+
end
|
52
|
+
|
53
|
+
params do
|
54
|
+
optional :item, type: Hash do
|
55
|
+
optional :beer
|
56
|
+
optional :wine
|
57
|
+
optional :grapefruit
|
58
|
+
exactly_one_of :beer, :wine, :grapefruit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
post '/nested-optional-hash' do
|
62
|
+
end
|
63
|
+
|
64
|
+
params do
|
65
|
+
requires :items, type: Array do
|
66
|
+
optional :beer
|
67
|
+
optional :wine
|
68
|
+
optional :grapefruit
|
69
|
+
exactly_one_of :beer, :wine, :grapefruit
|
70
|
+
end
|
71
|
+
end
|
72
|
+
post '/nested-array' do
|
73
|
+
end
|
74
|
+
|
75
|
+
params do
|
76
|
+
requires :items, type: Array do
|
77
|
+
requires :nested_items, type: Array do
|
78
|
+
optional :beer, :wine, :grapefruit, type: Boolean
|
79
|
+
exactly_one_of :beer, :wine, :grapefruit
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
post '/deeply-nested-array' do
|
84
|
+
end
|
85
|
+
end
|
12
86
|
end
|
13
87
|
end
|
14
|
-
let(:exactly_one_of_params) { %i[beer wine grapefruit] }
|
15
|
-
let(:validator) { described_class.new(exactly_one_of_params, {}, false, scope.new) }
|
16
88
|
|
17
|
-
|
89
|
+
def app
|
90
|
+
ValidationsSpec::ExactlyOneOfValidatorSpec::API
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when all params are present' do
|
94
|
+
let(:path) { '/' }
|
18
95
|
let(:params) { { beer: true, wine: true, grapefruit: true } }
|
19
96
|
|
20
|
-
it '
|
21
|
-
|
22
|
-
|
23
|
-
|
97
|
+
it 'returns a validation error' do
|
98
|
+
validate
|
99
|
+
expect(last_response.status).to eq 400
|
100
|
+
expect(JSON.parse(last_response.body)).to eq(
|
101
|
+
'beer,wine,grapefruit' => ['are missing, exactly one parameter must be provided']
|
102
|
+
)
|
24
103
|
end
|
25
104
|
|
26
105
|
context 'mixed with other params' do
|
27
|
-
let(:
|
106
|
+
let(:path) { '/mixed-params' }
|
107
|
+
let(:params) { { beer: true, wine: true, grapefruit: true, other: true } }
|
28
108
|
|
29
|
-
it '
|
30
|
-
|
31
|
-
|
32
|
-
|
109
|
+
it 'returns a validation error' do
|
110
|
+
validate
|
111
|
+
expect(last_response.status).to eq 400
|
112
|
+
expect(JSON.parse(last_response.body)).to eq(
|
113
|
+
'beer,wine,grapefruit' => ['are missing, exactly one parameter must be provided']
|
114
|
+
)
|
33
115
|
end
|
34
116
|
end
|
35
117
|
end
|
36
118
|
|
37
|
-
context 'when a subset of
|
119
|
+
context 'when a subset of params are present' do
|
120
|
+
let(:path) { '/' }
|
38
121
|
let(:params) { { beer: true, grapefruit: true } }
|
39
122
|
|
40
|
-
it '
|
41
|
-
|
42
|
-
|
43
|
-
|
123
|
+
it 'returns a validation error' do
|
124
|
+
validate
|
125
|
+
expect(last_response.status).to eq 400
|
126
|
+
expect(JSON.parse(last_response.body)).to eq(
|
127
|
+
'beer,wine,grapefruit' => ['are missing, exactly one parameter must be provided']
|
128
|
+
)
|
44
129
|
end
|
45
130
|
end
|
46
131
|
|
47
|
-
context 'when
|
48
|
-
let(:
|
132
|
+
context 'when custom message is specified' do
|
133
|
+
let(:path) { '/custom-message' }
|
134
|
+
let(:params) { { beer: true, wine: true } }
|
49
135
|
|
50
|
-
it '
|
51
|
-
|
52
|
-
|
53
|
-
|
136
|
+
it 'returns a validation error' do
|
137
|
+
validate
|
138
|
+
expect(last_response.status).to eq 400
|
139
|
+
expect(JSON.parse(last_response.body)).to eq(
|
140
|
+
'beer,wine,grapefruit' => ['you should choose one']
|
141
|
+
)
|
54
142
|
end
|
55
143
|
end
|
56
144
|
|
57
|
-
context 'when
|
145
|
+
context 'when exacly one param is present' do
|
146
|
+
let(:path) { '/' }
|
147
|
+
let(:params) { { beer: true, somethingelse: true } }
|
148
|
+
|
149
|
+
it 'does not return a validation error' do
|
150
|
+
validate
|
151
|
+
expect(last_response.status).to eq 201
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when none of the params are present' do
|
156
|
+
let(:path) { '/' }
|
58
157
|
let(:params) { { somethingelse: true } }
|
59
158
|
|
60
|
-
it '
|
61
|
-
|
62
|
-
|
63
|
-
|
159
|
+
it 'returns a validation error' do
|
160
|
+
validate
|
161
|
+
expect(last_response.status).to eq 400
|
162
|
+
expect(JSON.parse(last_response.body)).to eq(
|
163
|
+
'beer,wine,grapefruit' => ['are missing, exactly one parameter must be provided']
|
164
|
+
)
|
64
165
|
end
|
65
166
|
end
|
66
167
|
|
67
|
-
context 'when
|
68
|
-
let(:
|
168
|
+
context 'when params are nested inside required hash' do
|
169
|
+
let(:path) { '/nested-hash' }
|
170
|
+
let(:params) { { item: { beer: true, wine: true } } }
|
171
|
+
|
172
|
+
it 'returns a validation error with full names of the params' do
|
173
|
+
validate
|
174
|
+
expect(last_response.status).to eq 400
|
175
|
+
expect(JSON.parse(last_response.body)).to eq(
|
176
|
+
'item[beer],item[wine],item[grapefruit]' => ['are missing, exactly one parameter must be provided']
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'when params are nested inside optional hash' do
|
182
|
+
let(:path) { '/nested-optional-hash' }
|
183
|
+
|
184
|
+
context 'when params are passed' do
|
185
|
+
let(:params) { { item: { beer: true, wine: true } } }
|
186
|
+
|
187
|
+
it 'returns a validation error with full names of the params' do
|
188
|
+
validate
|
189
|
+
expect(last_response.status).to eq 400
|
190
|
+
expect(JSON.parse(last_response.body)).to eq(
|
191
|
+
'item[beer],item[wine],item[grapefruit]' => ['are missing, exactly one parameter must be provided']
|
192
|
+
)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when params are empty' do
|
197
|
+
let(:params) { { other: true } }
|
198
|
+
|
199
|
+
it 'does not return a validation error' do
|
200
|
+
validate
|
201
|
+
expect(last_response.status).to eq 201
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'when params are nested inside array' do
|
207
|
+
let(:path) { '/nested-array' }
|
208
|
+
let(:params) { { items: [{ beer: true, wine: true }, { wine: true, grapefruit: true }] } }
|
209
|
+
|
210
|
+
it 'returns a validation error with full names of the params' do
|
211
|
+
validate
|
212
|
+
expect(last_response.status).to eq 400
|
213
|
+
expect(JSON.parse(last_response.body)).to eq(
|
214
|
+
'items[0][beer],items[0][wine],items[0][grapefruit]' => [
|
215
|
+
'are missing, exactly one parameter must be provided'
|
216
|
+
],
|
217
|
+
'items[1][beer],items[1][wine],items[1][grapefruit]' => [
|
218
|
+
'are missing, exactly one parameter must be provided'
|
219
|
+
]
|
220
|
+
)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context 'when params are deeply nested' do
|
225
|
+
let(:path) { '/deeply-nested-array' }
|
226
|
+
let(:params) { { items: [{ nested_items: [{ beer: true, wine: true }] }] } }
|
69
227
|
|
70
|
-
it '
|
71
|
-
|
228
|
+
it 'returns a validation error with full names of the params' do
|
229
|
+
validate
|
230
|
+
expect(last_response.status).to eq 400
|
231
|
+
expect(JSON.parse(last_response.body)).to eq(
|
232
|
+
'items[0][nested_items][0][beer],items[0][nested_items][0][wine],items[0][nested_items][0][grapefruit]' => [
|
233
|
+
'are missing, exactly one parameter must be provided'
|
234
|
+
]
|
235
|
+
)
|
72
236
|
end
|
73
237
|
end
|
74
238
|
end
|
@@ -2,61 +2,218 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Grape::Validations::MutualExclusionValidator do
|
4
4
|
describe '#validate!' do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
subject(:validate) { post path, params }
|
6
|
+
|
7
|
+
module ValidationsSpec
|
8
|
+
module MutualExclusionValidatorSpec
|
9
|
+
class API < Grape::API
|
10
|
+
rescue_from Grape::Exceptions::ValidationErrors do |e|
|
11
|
+
error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
|
12
|
+
end
|
13
|
+
|
14
|
+
params do
|
15
|
+
optional :beer
|
16
|
+
optional :wine
|
17
|
+
optional :grapefruit
|
18
|
+
mutually_exclusive :beer, :wine, :grapefruit
|
19
|
+
end
|
20
|
+
post do
|
21
|
+
end
|
22
|
+
|
23
|
+
params do
|
24
|
+
optional :beer
|
25
|
+
optional :wine
|
26
|
+
optional :grapefruit
|
27
|
+
optional :other
|
28
|
+
mutually_exclusive :beer, :wine, :grapefruit
|
29
|
+
end
|
30
|
+
post 'mixed-params' do
|
31
|
+
end
|
32
|
+
|
33
|
+
params do
|
34
|
+
optional :beer
|
35
|
+
optional :wine
|
36
|
+
optional :grapefruit
|
37
|
+
mutually_exclusive :beer, :wine, :grapefruit, message: 'you should not mix beer and wine'
|
38
|
+
end
|
39
|
+
post '/custom-message' do
|
40
|
+
end
|
41
|
+
|
42
|
+
params do
|
43
|
+
requires :item, type: Hash do
|
44
|
+
optional :beer
|
45
|
+
optional :wine
|
46
|
+
optional :grapefruit
|
47
|
+
mutually_exclusive :beer, :wine, :grapefruit
|
48
|
+
end
|
49
|
+
end
|
50
|
+
post '/nested-hash' do
|
51
|
+
end
|
52
|
+
|
53
|
+
params do
|
54
|
+
optional :item, type: Hash do
|
55
|
+
optional :beer
|
56
|
+
optional :wine
|
57
|
+
optional :grapefruit
|
58
|
+
mutually_exclusive :beer, :wine, :grapefruit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
post '/nested-optional-hash' do
|
62
|
+
end
|
63
|
+
|
64
|
+
params do
|
65
|
+
requires :items, type: Array do
|
66
|
+
optional :beer
|
67
|
+
optional :wine
|
68
|
+
optional :grapefruit
|
69
|
+
mutually_exclusive :beer, :wine, :grapefruit
|
70
|
+
end
|
71
|
+
end
|
72
|
+
post '/nested-array' do
|
73
|
+
end
|
74
|
+
|
75
|
+
params do
|
76
|
+
requires :items, type: Array do
|
77
|
+
requires :nested_items, type: Array do
|
78
|
+
optional :beer, :wine, :grapefruit, type: Boolean
|
79
|
+
mutually_exclusive :beer, :wine, :grapefruit
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
post '/deeply-nested-array' do
|
84
|
+
end
|
9
85
|
end
|
10
86
|
end
|
11
87
|
end
|
12
|
-
|
13
|
-
|
88
|
+
|
89
|
+
def app
|
90
|
+
ValidationsSpec::MutualExclusionValidatorSpec::API
|
91
|
+
end
|
14
92
|
|
15
93
|
context 'when all mutually exclusive params are present' do
|
94
|
+
let(:path) { '/' }
|
16
95
|
let(:params) { { beer: true, wine: true, grapefruit: true } }
|
17
96
|
|
18
|
-
it '
|
19
|
-
|
20
|
-
|
21
|
-
|
97
|
+
it 'returns a validation error' do
|
98
|
+
validate
|
99
|
+
expect(last_response.status).to eq 400
|
100
|
+
expect(JSON.parse(last_response.body)).to eq(
|
101
|
+
'beer,wine,grapefruit' => ['are mutually exclusive']
|
102
|
+
)
|
22
103
|
end
|
23
104
|
|
24
105
|
context 'mixed with other params' do
|
25
|
-
let(:
|
106
|
+
let(:path) { '/mixed-params' }
|
107
|
+
let(:params) { { beer: true, wine: true, grapefruit: true, other: true } }
|
26
108
|
|
27
|
-
it '
|
28
|
-
|
29
|
-
|
30
|
-
|
109
|
+
it 'returns a validation error' do
|
110
|
+
validate
|
111
|
+
expect(last_response.status).to eq 400
|
112
|
+
expect(JSON.parse(last_response.body)).to eq(
|
113
|
+
'beer,wine,grapefruit' => ['are mutually exclusive']
|
114
|
+
)
|
31
115
|
end
|
32
116
|
end
|
33
117
|
end
|
34
118
|
|
35
119
|
context 'when a subset of mutually exclusive params are present' do
|
120
|
+
let(:path) { '/' }
|
36
121
|
let(:params) { { beer: true, grapefruit: true } }
|
37
122
|
|
38
|
-
it '
|
39
|
-
|
40
|
-
|
41
|
-
|
123
|
+
it 'returns a validation error' do
|
124
|
+
validate
|
125
|
+
expect(last_response.status).to eq 400
|
126
|
+
expect(JSON.parse(last_response.body)).to eq(
|
127
|
+
'beer,grapefruit' => ['are mutually exclusive']
|
128
|
+
)
|
42
129
|
end
|
43
130
|
end
|
44
131
|
|
45
|
-
context 'when
|
46
|
-
let(:
|
132
|
+
context 'when custom message is specified' do
|
133
|
+
let(:path) { '/custom-message' }
|
134
|
+
let(:params) { { beer: true, wine: true } }
|
47
135
|
|
48
|
-
it '
|
49
|
-
|
50
|
-
|
51
|
-
|
136
|
+
it 'returns a validation error' do
|
137
|
+
validate
|
138
|
+
expect(last_response.status).to eq 400
|
139
|
+
expect(JSON.parse(last_response.body)).to eq(
|
140
|
+
'beer,wine' => ['you should not mix beer and wine']
|
141
|
+
)
|
52
142
|
end
|
53
143
|
end
|
54
144
|
|
55
145
|
context 'when no mutually exclusive params are present' do
|
146
|
+
let(:path) { '/' }
|
56
147
|
let(:params) { { beer: true, somethingelse: true } }
|
57
148
|
|
58
|
-
it '
|
59
|
-
|
149
|
+
it 'does not return a validation error' do
|
150
|
+
validate
|
151
|
+
expect(last_response.status).to eq 201
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when mutually exclusive params are nested inside required hash' do
|
156
|
+
let(:path) { '/nested-hash' }
|
157
|
+
let(:params) { { item: { beer: true, wine: true } } }
|
158
|
+
|
159
|
+
it 'returns a validation error with full names of the params' do
|
160
|
+
validate
|
161
|
+
expect(last_response.status).to eq 400
|
162
|
+
expect(JSON.parse(last_response.body)).to eq(
|
163
|
+
'item[beer],item[wine]' => ['are mutually exclusive']
|
164
|
+
)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'when mutually exclusive params are nested inside optional hash' do
|
169
|
+
let(:path) { '/nested-optional-hash' }
|
170
|
+
|
171
|
+
context 'when params are passed' do
|
172
|
+
let(:params) { { item: { beer: true, wine: true } } }
|
173
|
+
|
174
|
+
it 'returns a validation error with full names of the params' do
|
175
|
+
validate
|
176
|
+
expect(last_response.status).to eq 400
|
177
|
+
expect(JSON.parse(last_response.body)).to eq(
|
178
|
+
'item[beer],item[wine]' => ['are mutually exclusive']
|
179
|
+
)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'when params are empty' do
|
184
|
+
let(:params) { {} }
|
185
|
+
|
186
|
+
it 'does not return a validation error' do
|
187
|
+
validate
|
188
|
+
expect(last_response.status).to eq 201
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'when mutually exclusive params are nested inside array' do
|
194
|
+
let(:path) { '/nested-array' }
|
195
|
+
let(:params) { { items: [{ beer: true, wine: true }, { wine: true, grapefruit: true }] } }
|
196
|
+
|
197
|
+
it 'returns a validation error with full names of the params' do
|
198
|
+
validate
|
199
|
+
expect(last_response.status).to eq 400
|
200
|
+
expect(JSON.parse(last_response.body)).to eq(
|
201
|
+
'items[0][beer],items[0][wine]' => ['are mutually exclusive'],
|
202
|
+
'items[1][wine],items[1][grapefruit]' => ['are mutually exclusive']
|
203
|
+
)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'when mutually exclusive params are deeply nested' do
|
208
|
+
let(:path) { '/deeply-nested-array' }
|
209
|
+
let(:params) { { items: [{ nested_items: [{ beer: true, wine: true }] }] } }
|
210
|
+
|
211
|
+
it 'returns a validation error with full names of the params' do
|
212
|
+
validate
|
213
|
+
expect(last_response.status).to eq 400
|
214
|
+
expect(JSON.parse(last_response.body)).to eq(
|
215
|
+
'items[0][nested_items][0][beer],items[0][nested_items][0][wine]' => ['are mutually exclusive']
|
216
|
+
)
|
60
217
|
end
|
61
218
|
end
|
62
219
|
end
|