grape-security 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +45 -0
- data/.rspec +2 -0
- data/.rubocop.yml +70 -0
- data/.travis.yml +18 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +314 -0
- data/CONTRIBUTING.md +118 -0
- data/Gemfile +21 -0
- data/Guardfile +14 -0
- data/LICENSE +20 -0
- data/README.md +1777 -0
- data/RELEASING.md +105 -0
- data/Rakefile +69 -0
- data/UPGRADING.md +124 -0
- data/grape-security.gemspec +39 -0
- data/grape.png +0 -0
- data/lib/grape.rb +99 -0
- data/lib/grape/api.rb +646 -0
- data/lib/grape/cookies.rb +39 -0
- data/lib/grape/endpoint.rb +533 -0
- data/lib/grape/error_formatter/base.rb +31 -0
- data/lib/grape/error_formatter/json.rb +15 -0
- data/lib/grape/error_formatter/txt.rb +16 -0
- data/lib/grape/error_formatter/xml.rb +15 -0
- data/lib/grape/exceptions/base.rb +66 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +10 -0
- data/lib/grape/exceptions/invalid_formatter.rb +10 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +10 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +10 -0
- data/lib/grape/exceptions/missing_mime_type.rb +10 -0
- data/lib/grape/exceptions/missing_option.rb +10 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +10 -0
- data/lib/grape/exceptions/unknown_options.rb +10 -0
- data/lib/grape/exceptions/unknown_validator.rb +10 -0
- data/lib/grape/exceptions/validation.rb +26 -0
- data/lib/grape/exceptions/validation_errors.rb +43 -0
- data/lib/grape/formatter/base.rb +31 -0
- data/lib/grape/formatter/json.rb +12 -0
- data/lib/grape/formatter/serializable_hash.rb +35 -0
- data/lib/grape/formatter/txt.rb +11 -0
- data/lib/grape/formatter/xml.rb +12 -0
- data/lib/grape/http/request.rb +26 -0
- data/lib/grape/locale/en.yml +32 -0
- data/lib/grape/middleware/auth/base.rb +30 -0
- data/lib/grape/middleware/auth/basic.rb +13 -0
- data/lib/grape/middleware/auth/digest.rb +13 -0
- data/lib/grape/middleware/auth/oauth2.rb +83 -0
- data/lib/grape/middleware/base.rb +62 -0
- data/lib/grape/middleware/error.rb +89 -0
- data/lib/grape/middleware/filter.rb +17 -0
- data/lib/grape/middleware/formatter.rb +150 -0
- data/lib/grape/middleware/globals.rb +13 -0
- data/lib/grape/middleware/versioner.rb +32 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +67 -0
- data/lib/grape/middleware/versioner/header.rb +132 -0
- data/lib/grape/middleware/versioner/param.rb +42 -0
- data/lib/grape/middleware/versioner/path.rb +52 -0
- data/lib/grape/namespace.rb +23 -0
- data/lib/grape/parser/base.rb +29 -0
- data/lib/grape/parser/json.rb +11 -0
- data/lib/grape/parser/xml.rb +11 -0
- data/lib/grape/path.rb +70 -0
- data/lib/grape/route.rb +27 -0
- data/lib/grape/util/content_types.rb +18 -0
- data/lib/grape/util/deep_merge.rb +23 -0
- data/lib/grape/util/hash_stack.rb +120 -0
- data/lib/grape/validations.rb +322 -0
- data/lib/grape/validations/coerce.rb +63 -0
- data/lib/grape/validations/default.rb +25 -0
- data/lib/grape/validations/exactly_one_of.rb +26 -0
- data/lib/grape/validations/mutual_exclusion.rb +25 -0
- data/lib/grape/validations/presence.rb +16 -0
- data/lib/grape/validations/regexp.rb +12 -0
- data/lib/grape/validations/values.rb +23 -0
- data/lib/grape/version.rb +3 -0
- data/spec/grape/api_spec.rb +2571 -0
- data/spec/grape/endpoint_spec.rb +784 -0
- data/spec/grape/entity_spec.rb +324 -0
- data/spec/grape/exceptions/invalid_formatter_spec.rb +18 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +18 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +18 -0
- data/spec/grape/exceptions/missing_option_spec.rb +18 -0
- data/spec/grape/exceptions/unknown_options_spec.rb +18 -0
- data/spec/grape/exceptions/unknown_validator_spec.rb +18 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +19 -0
- data/spec/grape/middleware/auth/basic_spec.rb +31 -0
- data/spec/grape/middleware/auth/digest_spec.rb +47 -0
- data/spec/grape/middleware/auth/oauth2_spec.rb +135 -0
- data/spec/grape/middleware/base_spec.rb +58 -0
- data/spec/grape/middleware/error_spec.rb +45 -0
- data/spec/grape/middleware/exception_spec.rb +184 -0
- data/spec/grape/middleware/formatter_spec.rb +258 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +121 -0
- data/spec/grape/middleware/versioner/header_spec.rb +302 -0
- data/spec/grape/middleware/versioner/param_spec.rb +58 -0
- data/spec/grape/middleware/versioner/path_spec.rb +44 -0
- data/spec/grape/middleware/versioner_spec.rb +22 -0
- data/spec/grape/path_spec.rb +229 -0
- data/spec/grape/util/hash_stack_spec.rb +132 -0
- data/spec/grape/validations/coerce_spec.rb +208 -0
- data/spec/grape/validations/default_spec.rb +123 -0
- data/spec/grape/validations/exactly_one_of_spec.rb +71 -0
- data/spec/grape/validations/mutual_exclusion_spec.rb +61 -0
- data/spec/grape/validations/presence_spec.rb +142 -0
- data/spec/grape/validations/regexp_spec.rb +40 -0
- data/spec/grape/validations/values_spec.rb +152 -0
- data/spec/grape/validations/zh-CN.yml +10 -0
- data/spec/grape/validations_spec.rb +994 -0
- data/spec/shared/versioning_examples.rb +121 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/basic_auth_encode_helpers.rb +3 -0
- data/spec/support/content_type_helpers.rb +11 -0
- data/spec/support/versioned_helpers.rb +50 -0
- metadata +421 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Grape::Validations::CoerceValidator do
|
5
|
+
subject do
|
6
|
+
Class.new(Grape::API)
|
7
|
+
end
|
8
|
+
|
9
|
+
def app
|
10
|
+
subject
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'coerce' do
|
14
|
+
|
15
|
+
context "i18n" do
|
16
|
+
|
17
|
+
after :each do
|
18
|
+
I18n.locale = :en
|
19
|
+
end
|
20
|
+
|
21
|
+
it "i18n error on malformed input" do
|
22
|
+
I18n.load_path << File.expand_path('../zh-CN.yml', __FILE__)
|
23
|
+
I18n.reload!
|
24
|
+
I18n.locale = 'zh-CN'.to_sym
|
25
|
+
subject.params do
|
26
|
+
requires :age, type: Integer
|
27
|
+
end
|
28
|
+
subject.get '/single' do
|
29
|
+
'int works'
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/single', age: '43a'
|
33
|
+
expect(last_response.status).to eq(400)
|
34
|
+
expect(last_response.body).to eq('年龄格式不正确')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'gives an english fallback error when default locale message is blank' do
|
38
|
+
I18n.locale = 'pt-BR'.to_sym
|
39
|
+
subject.params do
|
40
|
+
requires :age, type: Integer
|
41
|
+
end
|
42
|
+
subject.get '/single' do
|
43
|
+
'int works'
|
44
|
+
end
|
45
|
+
|
46
|
+
get '/single', age: '43a'
|
47
|
+
expect(last_response.status).to eq(400)
|
48
|
+
expect(last_response.body).to eq('age is invalid')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'error on malformed input' do
|
54
|
+
subject.params do
|
55
|
+
requires :int, type: Integer
|
56
|
+
end
|
57
|
+
subject.get '/single' do
|
58
|
+
'int works'
|
59
|
+
end
|
60
|
+
|
61
|
+
get '/single', int: '43a'
|
62
|
+
expect(last_response.status).to eq(400)
|
63
|
+
expect(last_response.body).to eq('int is invalid')
|
64
|
+
|
65
|
+
get '/single', int: '43'
|
66
|
+
expect(last_response.status).to eq(200)
|
67
|
+
expect(last_response.body).to eq('int works')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'error on malformed input (Array)' do
|
71
|
+
subject.params do
|
72
|
+
requires :ids, type: Array[Integer]
|
73
|
+
end
|
74
|
+
subject.get '/array' do
|
75
|
+
'array int works'
|
76
|
+
end
|
77
|
+
|
78
|
+
get 'array', ids: ['1', '2', 'az']
|
79
|
+
expect(last_response.status).to eq(400)
|
80
|
+
expect(last_response.body).to eq('ids is invalid')
|
81
|
+
|
82
|
+
get 'array', ids: ['1', '2', '890']
|
83
|
+
expect(last_response.status).to eq(200)
|
84
|
+
expect(last_response.body).to eq('array int works')
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'complex objects' do
|
88
|
+
module CoerceValidatorSpec
|
89
|
+
class User
|
90
|
+
include Virtus.model
|
91
|
+
attribute :id, Integer
|
92
|
+
attribute :name, String
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'error on malformed input for complex objects' do
|
97
|
+
subject.params do
|
98
|
+
requires :user, type: CoerceValidatorSpec::User
|
99
|
+
end
|
100
|
+
subject.get '/user' do
|
101
|
+
'complex works'
|
102
|
+
end
|
103
|
+
|
104
|
+
get '/user', user: "32"
|
105
|
+
expect(last_response.status).to eq(400)
|
106
|
+
expect(last_response.body).to eq('user is invalid')
|
107
|
+
|
108
|
+
get '/user', user: { id: 32, name: 'Bob' }
|
109
|
+
expect(last_response.status).to eq(200)
|
110
|
+
expect(last_response.body).to eq('complex works')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'coerces' do
|
115
|
+
it 'Integer' do
|
116
|
+
subject.params do
|
117
|
+
requires :int, coerce: Integer
|
118
|
+
end
|
119
|
+
subject.get '/int' do
|
120
|
+
params[:int].class
|
121
|
+
end
|
122
|
+
|
123
|
+
get '/int', int: "45"
|
124
|
+
expect(last_response.status).to eq(200)
|
125
|
+
expect(last_response.body).to eq('Integer')
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'Array of Integers' do
|
129
|
+
subject.params do
|
130
|
+
requires :arry, coerce: Array[Integer]
|
131
|
+
end
|
132
|
+
subject.get '/array' do
|
133
|
+
params[:arry][0].class
|
134
|
+
end
|
135
|
+
|
136
|
+
get '/array', arry: ['1', '2', '3']
|
137
|
+
expect(last_response.status).to eq(200)
|
138
|
+
expect(last_response.body).to eq('Integer')
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'Array of Bools' do
|
142
|
+
subject.params do
|
143
|
+
requires :arry, coerce: Array[Virtus::Attribute::Boolean]
|
144
|
+
end
|
145
|
+
subject.get '/array' do
|
146
|
+
params[:arry][0].class
|
147
|
+
end
|
148
|
+
|
149
|
+
get 'array', arry: [1, 0]
|
150
|
+
expect(last_response.status).to eq(200)
|
151
|
+
expect(last_response.body).to eq('TrueClass')
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'Bool' do
|
155
|
+
subject.params do
|
156
|
+
requires :bool, coerce: Virtus::Attribute::Boolean
|
157
|
+
end
|
158
|
+
subject.get '/bool' do
|
159
|
+
params[:bool].class
|
160
|
+
end
|
161
|
+
|
162
|
+
get '/bool', bool: 1
|
163
|
+
expect(last_response.status).to eq(200)
|
164
|
+
expect(last_response.body).to eq('TrueClass')
|
165
|
+
|
166
|
+
get '/bool', bool: 0
|
167
|
+
expect(last_response.status).to eq(200)
|
168
|
+
expect(last_response.body).to eq('FalseClass')
|
169
|
+
|
170
|
+
get '/bool', bool: 'false'
|
171
|
+
expect(last_response.status).to eq(200)
|
172
|
+
expect(last_response.body).to eq('FalseClass')
|
173
|
+
|
174
|
+
get '/bool', bool: 'true'
|
175
|
+
expect(last_response.status).to eq(200)
|
176
|
+
expect(last_response.body).to eq('TrueClass')
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'file' do
|
180
|
+
subject.params do
|
181
|
+
requires :file, coerce: Rack::Multipart::UploadedFile
|
182
|
+
end
|
183
|
+
subject.post '/upload' do
|
184
|
+
params[:file].filename
|
185
|
+
end
|
186
|
+
|
187
|
+
post '/upload', file: Rack::Test::UploadedFile.new(__FILE__)
|
188
|
+
expect(last_response.status).to eq(201)
|
189
|
+
expect(last_response.body).to eq(File.basename(__FILE__).to_s)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'Nests integers' do
|
193
|
+
subject.params do
|
194
|
+
requires :integers, type: Hash do
|
195
|
+
requires :int, coerce: Integer
|
196
|
+
end
|
197
|
+
end
|
198
|
+
subject.get '/int' do
|
199
|
+
params[:integers][:int].class
|
200
|
+
end
|
201
|
+
|
202
|
+
get '/int', integers: { int: "45" }
|
203
|
+
expect(last_response.status).to eq(200)
|
204
|
+
expect(last_response.body).to eq('Integer')
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Validations::DefaultValidator do
|
4
|
+
|
5
|
+
module ValidationsSpec
|
6
|
+
module DefaultValidatorSpec
|
7
|
+
class API < Grape::API
|
8
|
+
default_format :json
|
9
|
+
|
10
|
+
params do
|
11
|
+
optional :id
|
12
|
+
optional :type, default: 'default-type'
|
13
|
+
end
|
14
|
+
get '/' do
|
15
|
+
{ id: params[:id], type: params[:type] }
|
16
|
+
end
|
17
|
+
|
18
|
+
params do
|
19
|
+
optional :type1, default: 'default-type1'
|
20
|
+
optional :type2, default: 'default-type2'
|
21
|
+
end
|
22
|
+
get '/user' do
|
23
|
+
{ type1: params[:type1], type2: params[:type2] }
|
24
|
+
end
|
25
|
+
|
26
|
+
params do
|
27
|
+
requires :id
|
28
|
+
optional :type1, default: 'default-type1'
|
29
|
+
optional :type2, default: 'default-type2'
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/message' do
|
33
|
+
{ id: params[:id], type1: params[:type1], type2: params[:type2] }
|
34
|
+
end
|
35
|
+
|
36
|
+
params do
|
37
|
+
optional :random, default: -> { Random.rand }
|
38
|
+
optional :not_random, default: Random.rand
|
39
|
+
end
|
40
|
+
get '/numbers' do
|
41
|
+
{ random_number: params[:random], non_random_number: params[:non_random_number] }
|
42
|
+
end
|
43
|
+
|
44
|
+
params do
|
45
|
+
# NOTE: The :foo parameter could be made required with json body
|
46
|
+
# params, and then an empty hash would be valid. With query parameters
|
47
|
+
# it must be optional if it isn't provided at all, as otherwise
|
48
|
+
# the validaton for the Hash itself fails because there is no such
|
49
|
+
# thing as an empty hash.
|
50
|
+
optional :foo, type: Hash do
|
51
|
+
optional :bar, default: 'foo-bar'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
get '/group' do
|
55
|
+
{ foo_bar: params[:foo][:bar] }
|
56
|
+
end
|
57
|
+
|
58
|
+
params do
|
59
|
+
optional :array, type: Array do
|
60
|
+
requires :name
|
61
|
+
optional :with_default, default: 'default'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
get '/array' do
|
65
|
+
{ array: params[:array] }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def app
|
72
|
+
ValidationsSpec::DefaultValidatorSpec::API
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'set default value for optional param' do
|
76
|
+
get("/")
|
77
|
+
expect(last_response.status).to eq(200)
|
78
|
+
expect(last_response.body).to eq({ id: nil, type: 'default-type' }.to_json)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'set default values for optional params' do
|
82
|
+
get("/user")
|
83
|
+
expect(last_response.status).to eq(200)
|
84
|
+
expect(last_response.body).to eq({ type1: 'default-type1', type2: 'default-type2' }.to_json)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'set default values for missing params in the request' do
|
88
|
+
get("/user?type2=value2")
|
89
|
+
expect(last_response.status).to eq(200)
|
90
|
+
expect(last_response.body).to eq({ type1: 'default-type1', type2: 'value2' }.to_json)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'set default values for optional params and allow to use required fields in the same time' do
|
94
|
+
get("/message?id=1")
|
95
|
+
expect(last_response.status).to eq(200)
|
96
|
+
expect(last_response.body).to eq({ id: '1', type1: 'default-type1', type2: 'default-type2' }.to_json)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'sets lambda based defaults at the time of call' do
|
100
|
+
get("/numbers")
|
101
|
+
expect(last_response.status).to eq(200)
|
102
|
+
before = JSON.parse(last_response.body)
|
103
|
+
get("/numbers")
|
104
|
+
expect(last_response.status).to eq(200)
|
105
|
+
after = JSON.parse(last_response.body)
|
106
|
+
|
107
|
+
expect(before['non_random_number']).to eq(after['non_random_number'])
|
108
|
+
expect(before['random_number']).not_to eq(after['random_number'])
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'set default values for optional grouped params' do
|
112
|
+
get('/group')
|
113
|
+
expect(last_response.status).to eq(200)
|
114
|
+
expect(last_response.body).to eq({ foo_bar: 'foo-bar' }.to_json)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'sets default values for grouped arrays' do
|
118
|
+
get('/array?array[][name]=name&array[][name]=name2&array[][with_default]=bar2')
|
119
|
+
expect(last_response.status).to eq(200)
|
120
|
+
expect(last_response.body).to eq({ array: [{ name: "name", with_default: "default" }, { name: "name2", with_default: "bar2" }] }.to_json)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Validations::ExactlyOneOfValidator do
|
4
|
+
describe '#validate!' do
|
5
|
+
let(:scope) do
|
6
|
+
Struct.new(:opts) do
|
7
|
+
def params(arg); end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
let(:exactly_one_of_params) { [:beer, :wine, :grapefruit] }
|
11
|
+
let(:validator) { described_class.new(exactly_one_of_params, {}, false, scope.new) }
|
12
|
+
|
13
|
+
context 'when all restricted params are present' do
|
14
|
+
let(:params) { { beer: true, wine: true, grapefruit: true } }
|
15
|
+
|
16
|
+
it 'raises a validation exception' do
|
17
|
+
expect {
|
18
|
+
validator.validate! params
|
19
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'mixed with other params' do
|
23
|
+
let(:mixed_params) { params.merge!(other: true, andanother: true) }
|
24
|
+
|
25
|
+
it 'still raises a validation exception' do
|
26
|
+
expect {
|
27
|
+
validator.validate! mixed_params
|
28
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when a subset of restricted params are present' do
|
34
|
+
let(:params) { { beer: true, grapefruit: true } }
|
35
|
+
|
36
|
+
it 'raises a validation exception' do
|
37
|
+
expect {
|
38
|
+
validator.validate! params
|
39
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when params keys come as strings' do
|
44
|
+
let(:params) { { 'beer' => true, 'grapefruit' => true } }
|
45
|
+
|
46
|
+
it 'raises a validation exception' do
|
47
|
+
expect {
|
48
|
+
validator.validate! params
|
49
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when none of the restricted params is selected' do
|
54
|
+
let(:params) { { somethingelse: true } }
|
55
|
+
|
56
|
+
it 'raises a validation exception' do
|
57
|
+
expect {
|
58
|
+
validator.validate! params
|
59
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when exactly one of the restricted params is selected' do
|
64
|
+
let(:params) { { beer: true, somethingelse: true } }
|
65
|
+
|
66
|
+
it 'params' do
|
67
|
+
expect(validator.validate!(params)).to eql params
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Validations::MutualExclusionValidator do
|
4
|
+
describe '#validate!' do
|
5
|
+
let(:scope) do
|
6
|
+
Struct.new(:opts) do
|
7
|
+
def params(arg); end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
let(:mutually_exclusive_params) { [:beer, :wine, :grapefruit] }
|
11
|
+
let(:validator) { described_class.new(mutually_exclusive_params, {}, false, scope.new) }
|
12
|
+
|
13
|
+
context 'when all mutually exclusive params are present' do
|
14
|
+
let(:params) { { beer: true, wine: true, grapefruit: true } }
|
15
|
+
|
16
|
+
it 'raises a validation exception' do
|
17
|
+
expect {
|
18
|
+
validator.validate! params
|
19
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'mixed with other params' do
|
23
|
+
let(:mixed_params) { params.merge!(other: true, andanother: true) }
|
24
|
+
|
25
|
+
it 'still raises a validation exception' do
|
26
|
+
expect {
|
27
|
+
validator.validate! mixed_params
|
28
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when a subset of mutually exclusive params are present' do
|
34
|
+
let(:params) { { beer: true, grapefruit: true } }
|
35
|
+
|
36
|
+
it 'raises a validation exception' do
|
37
|
+
expect {
|
38
|
+
validator.validate! params
|
39
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when params keys come as strings' do
|
44
|
+
let(:params) { { 'beer' => true, 'grapefruit' => true } }
|
45
|
+
|
46
|
+
it 'raises a validation exception' do
|
47
|
+
expect {
|
48
|
+
validator.validate! params
|
49
|
+
}.to raise_error(Grape::Exceptions::Validation)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when no mutually exclusive params are present' do
|
54
|
+
let(:params) { { beer: true, somethingelse: true } }
|
55
|
+
|
56
|
+
it 'params' do
|
57
|
+
expect(validator.validate!(params)).to eql params
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|