sinatra-param2 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +77 -0
  4. data/LICENSE +19 -0
  5. data/README.md +190 -0
  6. data/Rakefile +18 -0
  7. data/build/reports/assets/0.10.1/application.css +799 -0
  8. data/build/reports/assets/0.10.1/application.js +1707 -0
  9. data/build/reports/assets/0.10.1/colorbox/border.png +0 -0
  10. data/build/reports/assets/0.10.1/colorbox/controls.png +0 -0
  11. data/build/reports/assets/0.10.1/colorbox/loading.gif +0 -0
  12. data/build/reports/assets/0.10.1/colorbox/loading_background.png +0 -0
  13. data/build/reports/assets/0.10.1/favicon_green.png +0 -0
  14. data/build/reports/assets/0.10.1/favicon_red.png +0 -0
  15. data/build/reports/assets/0.10.1/favicon_yellow.png +0 -0
  16. data/build/reports/assets/0.10.1/loading.gif +0 -0
  17. data/build/reports/assets/0.10.1/magnify.png +0 -0
  18. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  19. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  20. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  21. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  22. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  23. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  24. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  25. data/build/reports/assets/0.10.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  26. data/build/reports/assets/0.10.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
  27. data/build/reports/assets/0.10.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  28. data/build/reports/assets/0.10.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
  29. data/build/reports/assets/0.10.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
  30. data/build/reports/assets/0.10.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  31. data/build/reports/coverage.xml +165 -0
  32. data/build/reports/index.html +1643 -0
  33. data/example/Gemfile +7 -0
  34. data/example/Gemfile.lock +33 -0
  35. data/example/Procfile +1 -0
  36. data/example/app.rb +52 -0
  37. data/example/config.ru +6 -0
  38. data/lib/sinatra/param.rb +245 -0
  39. data/lib/sinatra/param/version.rb +5 -0
  40. data/sinatra-param2.gemspec +27 -0
  41. data/spec/dummy/app.rb +346 -0
  42. data/spec/parameter_conjunctivity_spec.rb +34 -0
  43. data/spec/parameter_exclusivity_spec.rb +55 -0
  44. data/spec/parameter_inclusivity_spec.rb +30 -0
  45. data/spec/parameter_nested_validations_spec.rb +151 -0
  46. data/spec/parameter_raise_spec.rb +25 -0
  47. data/spec/parameter_spec.rb +19 -0
  48. data/spec/parameter_transformations_spec.rb +42 -0
  49. data/spec/parameter_type_coercion_spec.rb +211 -0
  50. data/spec/parameter_validations_spec.rb +247 -0
  51. data/spec/spec_helper.rb +29 -0
  52. metadata +190 -0
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Parameter Sets' do
4
+ describe 'all_or_none_of' do
5
+ it 'returns 400 on requests that have some but not all required parameters' do
6
+ params = [
7
+ {a: 1},
8
+ {b: 2, c: 3},
9
+ {a: 1, c: 3},
10
+ ]
11
+
12
+ params.each do |param|
13
+ get('/all_or_none_of', param) do |response|
14
+ expect(response.status).to eql 400
15
+ expect(JSON.parse(response.body)['message']).to match(/^Invalid parameters/)
16
+ end
17
+ end
18
+ end
19
+
20
+ it 'returns successfully for requests that have all parameters' do
21
+ param = {a: 1, b: 2, c: 3}
22
+
23
+ response = get("/all_or_none_of", param)
24
+ expect(response.status).to eql 200
25
+ expect(JSON.parse(response.body)['message']).to match(/OK/)
26
+ end
27
+
28
+ it 'returns successfully for requests that have none of the parameters' do
29
+ response = get("/all_or_none_of")
30
+ expect(response.status).to eql 200
31
+ expect(JSON.parse(response.body)['message']).to match(/OK/)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Parameter Sets' do
4
+ describe 'one_of' do
5
+ it 'returns 400 on requests that contain more than one mutually exclusive parameter' do
6
+ params = [
7
+ {a: 1, b: 2},
8
+ {b: 2, c: 3},
9
+ {a: 1, b: 2, c: 3}
10
+ ]
11
+
12
+ params.each do |param|
13
+ get('/one_of/3', param) do |response|
14
+ expect(response.status).to eql 400
15
+ expect(JSON.parse(response.body)['message']).to match(/^Invalid parameters/)
16
+ end
17
+ end
18
+ end
19
+
20
+ it 'returns 400 on requests that contain more than one mutually exclusive parameter' do
21
+ params = {a: 1, b: 2}
22
+
23
+ get('/one_of/2', params) do |response|
24
+ expect(response.status).to eql 400
25
+ expect(JSON.parse(response.body)['message']).to match(/^Invalid parameters/)
26
+ end
27
+ end
28
+
29
+ it 'returns successfully for requests that have one parameter' do
30
+ params = [
31
+ {a: 1},
32
+ {b: 2},
33
+ {c: 3}
34
+ ]
35
+
36
+ (1..3).each do |n|
37
+ params.each do |param|
38
+ get("/one_of/#{n}", param) do |response|
39
+ expect(response.status).to eql 200
40
+ expect(JSON.parse(response.body)['message']).to match(/OK/)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ it 'returns successfully for requests that have no parameter' do
47
+ (1..3).each do |n|
48
+ get("/one_of/#{n}") do |response|
49
+ expect(response.status).to eql 200
50
+ expect(JSON.parse(response.body)['message']).to match(/OK/)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Parameter Sets' do
4
+ describe 'any_of' do
5
+ it 'returns 400 on requests that contain fewer than one required parameter' do
6
+ get('/any_of', {}) do |response|
7
+ expect(response.status).to eql 400
8
+ expect(JSON.parse(response.body)['message']).to match(/Invalid parameters/)
9
+ end
10
+ end
11
+
12
+ it 'returns successfully for requests that have at least one parameter' do
13
+ params = [
14
+ {a: 1},
15
+ {b: 2},
16
+ {c: 3},
17
+ {a: 1, b: 2},
18
+ {b: 2, c: 3},
19
+ {a: 1, b: 2, c: 3}
20
+ ]
21
+
22
+ params.each do |param|
23
+ get("/any_of", param) do |response|
24
+ expect(response.status).to eql 200
25
+ expect(JSON.parse(response.body)['message']).to match(/OK/)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Nested Validation' do
4
+ context '' do
5
+ it 'should validate the children when the parent is present' do
6
+ params = {
7
+ :parent => {
8
+ :required_child => 1,
9
+ }
10
+ }
11
+
12
+ get("/validation/hash/nested_values", params) do |response|
13
+ expect(response.status).to eq(200)
14
+ expect(JSON.parse(response.body)['message']).to eq("OK")
15
+ end
16
+ end
17
+
18
+ it 'should be invalid when the parent is present but a nested validation fails' do
19
+ params = {
20
+ :parent => {
21
+ :optional_chlid => 'test'
22
+ }
23
+ }
24
+
25
+ get("/validation/hash/nested_values", params) do |response|
26
+ expect(response.status).to eq(400)
27
+ body = JSON.parse(response.body)
28
+ expect(body['message']).to eq("Parameter is required")
29
+ expect(body['errors']).to eq({
30
+ "parent[required_child]" => "Parameter is required"
31
+ })
32
+ end
33
+ end
34
+
35
+ it 'should not require sub params when the parent hash is not present and not required' do
36
+ params = {}
37
+ get("/validation/hash/nested_values", params) do |response|
38
+ expect(response.status).to eq(200)
39
+ expect(JSON.parse(response.body)['message']).to eq("OK")
40
+ end
41
+ end
42
+
43
+ it 'should allow arbitrary levels of nesting' do
44
+ params = {
45
+ :parent => {
46
+ :required_child => 1,
47
+ :nested_child => {
48
+ :required_sub_child => 'test'
49
+ }
50
+ }
51
+ }
52
+
53
+ get("/validation/hash/nested_values", params) do |response|
54
+ expect(response.status).to eq(200)
55
+ expect(JSON.parse(response.body)['message']).to eq("OK")
56
+ end
57
+ end
58
+
59
+ it 'should have the proper error message for multiple levels deep validation errors' do
60
+ params = {
61
+ :parent => {
62
+ :required_child => 1,
63
+ :nested_child => {
64
+ :required_sub_child => 'test',
65
+ :optional_sub_child => 'test'
66
+ }
67
+ }
68
+ }
69
+
70
+ get("/validation/hash/nested_values", params) do |response|
71
+ expect(response.status).to eq(400)
72
+ body = JSON.parse(response.body)
73
+ expect(body['message']).to eq("'test' is not a valid Integer")
74
+ expect(body['errors']).to eq({
75
+ "parent[nested_child][optional_sub_child]" => "'test' is not a valid Integer"
76
+ })
77
+ end
78
+ end
79
+
80
+ it 'should error when sub hash validation is tried on a non Hash parameter' do
81
+ params = {
82
+ :parent => {
83
+ :child => 'test'
84
+ }
85
+ }
86
+
87
+ get("/validation/hash/bad_nested_values", params) do |response|
88
+ expect(response.status).to eq(400)
89
+ body = JSON.parse(response.body)
90
+ expect(body['message']).to eq("Only the Hash parameter validation can use sub hash validation method")
91
+ expect(body['errors']).to eq({
92
+ "parent" => "Only the Hash parameter validation can use sub hash validation method"
93
+ })
94
+ end
95
+ end
96
+
97
+ it 'should work with one_of nested in a hash' do
98
+ params = {
99
+ :parent => {
100
+ :a => 'test'
101
+ }
102
+ }
103
+
104
+ get("/one_of/nested", params) do |response|
105
+ expect(response.status).to eq(200)
106
+ expect(JSON.parse(response.body)['message']).to eq("OK")
107
+ end
108
+ end
109
+
110
+ it "should error when one_of isn't satisfied in a nested hash" do
111
+ params = {
112
+ :parent => {
113
+ :a => 'test',
114
+ :b => 'test'
115
+ }
116
+ }
117
+
118
+ get("/one_of/nested", params) do |response|
119
+ expect(response.status).to eq(400)
120
+ expect(JSON.parse(response.body)['message']).to eq("Invalid parameters parent[[a, b, c]]")
121
+ end
122
+ end
123
+
124
+ it 'should work with any_of nested in a hash' do
125
+ params = {
126
+ :parent => {
127
+ :a => 'test'
128
+ }
129
+ }
130
+
131
+ get("/any_of/nested", params) do |response|
132
+ expect(response.status).to eq(200)
133
+ expect(JSON.parse(response.body)['message']).to eq("OK")
134
+ end
135
+ end
136
+
137
+ it "should error when one_of isn't satisfied in a nested hash" do
138
+ params = {
139
+ :parent => {
140
+ :d => 'test'
141
+ }
142
+ }
143
+
144
+ get("/any_of/nested", params) do |response|
145
+ expect(response.status).to eq(400)
146
+ expect(JSON.parse(response.body)['message']).to eq("Invalid parameters parent[[a, b, c]]")
147
+ end
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Exception' do
4
+ describe 'raise' do
5
+ it 'should raise error when option is specified' do
6
+ expect {
7
+ get('/raise/validation/required')
8
+ }.to raise_error(Sinatra::Param::InvalidParameterError)
9
+ end
10
+ end
11
+
12
+ it 'should raise error when more than one parameter is specified' do
13
+ params = {a: 1, b: 2, c: 3}
14
+ expect {
15
+ get('/raise/one_of/3', params)
16
+ }.to raise_error(Sinatra::Param::InvalidParameterError)
17
+ end
18
+
19
+ it 'should raise error when no parameters are specified' do
20
+ params = {}
21
+ expect {
22
+ get('/raise/any_of', params)
23
+ }.to raise_error(Sinatra::Param::InvalidParameterError)
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Parameter' do
4
+ it 'only sets parameters present in request or with a default value' do
5
+ get('/', a: 'a', b: 'b') do |response|
6
+ response_body = JSON.parse(response.body)
7
+ expect(response_body).to be_member('a')
8
+ expect(response_body).to be_member('b')
9
+ expect(response_body).to be_member('c')
10
+ expect(response_body).to_not be_member('d')
11
+ end
12
+ end
13
+
14
+ it 'stringifies parameters' do
15
+ get('/keys/stringify', q: 'test') do |response|
16
+ expect(response.body).to eq 'TEST'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Parameter Transformations' do
4
+ describe 'default' do
5
+ it 'sets a default value when none is given' do
6
+ get('/default') do |response|
7
+ expect(response.status).to eql 200
8
+ expect(JSON.parse(response.body)['sort']).to eql 'title'
9
+ end
10
+ end
11
+
12
+ it 'sets a default value from an empty hash' do
13
+ get('/default/hash') do |response|
14
+ expect(response.status).to eql 200
15
+ expect(JSON.parse(response.body)['attributes']).to eql Hash.new
16
+ end
17
+ end
18
+
19
+ it 'sets a default value from a proc' do
20
+ get('/default/proc') do |response|
21
+ expect(response.status).to eql 200
22
+ expect(JSON.parse(response.body)['year']).to eql 2014
23
+ end
24
+ end
25
+ end
26
+
27
+ describe 'transform' do
28
+ it 'transforms the input using to_proc' do
29
+ get('/transform', order: 'asc') do |response|
30
+ expect(response.status).to eql 200
31
+ expect(JSON.parse(response.body)['order']).to eql 'ASC'
32
+ end
33
+ end
34
+
35
+ it 'skips transformations when the value is nil' do
36
+ get('/transform/required') do |response|
37
+ expect(response.status).to eql 400
38
+ expect(JSON.parse(response.body)['message']).to eq("Parameter is required")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,211 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Parameter Types' do
4
+ describe 'String' do
5
+ it 'coerces strings' do
6
+ get('/coerce/string', arg: '1234') do |response|
7
+ expect(response.status).to eql 200
8
+ expect(JSON.parse(response.body)['arg']).to eq('1234')
9
+ end
10
+ end
11
+ end
12
+
13
+ describe 'Integer' do
14
+ it 'coerces integers' do
15
+ get('/coerce/integer', arg: '1234') do |response|
16
+ expect(response.status).to eql 200
17
+ expect(JSON.parse(response.body)['arg']).to eq(1234)
18
+ end
19
+ end
20
+
21
+ it 'returns 400 on requests when integer is invalid' do
22
+ get('/coerce/integer', arg: '123abc') do |response|
23
+ expect(response.status).to eql 400
24
+ expect(JSON.parse(response.body)['message']).to eq("'123abc' is not a valid Integer")
25
+ end
26
+ end
27
+ end
28
+
29
+ describe 'Float' do
30
+ it 'coerces floats' do
31
+ get('/coerce/float', arg: '1234') do |response|
32
+ expect(response.status).to eql 200
33
+ expect(JSON.parse(response.body)['arg']).to eq(1234.0)
34
+ end
35
+ end
36
+
37
+ it 'returns 400 on requests when float is invalid' do
38
+ get('/coerce/float', arg: '123abc') do |response|
39
+ expect(response.status).to eql 400
40
+ expect(JSON.parse(response.body)['message']).to eq("'123abc' is not a valid Float")
41
+ end
42
+ end
43
+ end
44
+
45
+ describe 'Time' do
46
+ it 'coerces time' do
47
+ get('/coerce/time', arg: '20130117') do |response|
48
+ expect(response.status).to eql 200
49
+ expect(JSON.parse(response.body)['arg']).to match(/2013-01-17 00:00:00/)
50
+ end
51
+ end
52
+
53
+ it 'returns 400 on requests when time is invalid' do
54
+ get('/coerce/time', arg: '123abc') do |response|
55
+ expect(response.status).to eql 400
56
+ expect(JSON.parse(response.body)['message']).to eq("'123abc' is not a valid Time")
57
+ end
58
+ end
59
+ end
60
+
61
+ describe 'Date' do
62
+ it 'coerces date' do
63
+ get('/coerce/date', arg: '20130117') do |response|
64
+ expect(response.status).to eql 200
65
+ expect(JSON.parse(response.body)['arg']).to eq('2013-01-17')
66
+ end
67
+ end
68
+
69
+ it 'returns 400 on requests when date is invalid' do
70
+ get('/coerce/date', arg: 'abc') do |response|
71
+ expect(response.status).to eql 400
72
+ expect(JSON.parse(response.body)['message']).to eq("'abc' is not a valid Date")
73
+ end
74
+ end
75
+ end
76
+
77
+ describe 'DateTime' do
78
+ it 'coerces datetimes' do
79
+ get('/coerce/datetime', arg: '20130117') do |response|
80
+ expect(response.status).to eql 200
81
+ expect(JSON.parse(response.body)['arg']).to eq('2013-01-17T00:00:00+00:00')
82
+ end
83
+ end
84
+
85
+ it 'returns 400 on requests when datetime is invalid' do
86
+ get('/coerce/datetime', arg: 'abc') do |response|
87
+ expect(response.status).to eql 400
88
+ expect(JSON.parse(response.body)['message']).to eq("'abc' is not a valid DateTime")
89
+ end
90
+ end
91
+ end
92
+
93
+ describe 'Array' do
94
+ it 'coerces arrays' do
95
+ get('/coerce/array', arg: '1,2,3,4,5') do |response|
96
+ expect(response.status).to eql 200
97
+ parsed_body = JSON.parse(response.body)
98
+ expect(parsed_body['arg']).to be_an(Array)
99
+ expect(parsed_body['arg']).to eq(%w(1 2 3 4 5))
100
+ end
101
+ end
102
+
103
+ it 'coerces arrays of size 1' do
104
+ get('/coerce/array', arg: '1') do |response|
105
+ expect(response.status).to eql 200
106
+ parsed_body = JSON.parse(response.body)
107
+ expect(parsed_body['arg']).to be_an(Array)
108
+ expect(parsed_body['arg']).to eq(%w(1))
109
+ end
110
+ end
111
+
112
+ it 'coerces arrays with arg[] style' do
113
+ get('/coerce/array', 'arg[]' => ['1','2','3','4','5']) do |response|
114
+ expect(response.status).to eql 200
115
+ parsed_body = JSON.parse(response.body)
116
+ expect(parsed_body['arg']).to be_an(Array)
117
+ expect(parsed_body['arg']).to eq(%w(1 2 3 4 5))
118
+ end
119
+ end
120
+
121
+ it 'coerces arrays when hash is given' do
122
+ get('/coerce/array', arg: { foo: 'bar', chunky: 'bacon' } ) do |response|
123
+ expect(response.status).to eql 200
124
+ parsed_body = JSON.parse(response.body)
125
+ expect(parsed_body['arg']).to be_an(Array)
126
+ expect(parsed_body['arg']).to eq([['foo', 'bar'], ['chunky', 'bacon']])
127
+ end
128
+ end
129
+ end
130
+
131
+ describe 'Hash' do
132
+ it 'coerces hashes' do
133
+ get('/coerce/hash', arg: 'a:b,c:d') do |response|
134
+ expect(response.status).to eql 200
135
+ parsed_body = JSON.parse(response.body)
136
+ expect(parsed_body['arg']).to be_an(Hash)
137
+ expect(parsed_body['arg']).to eq({ 'a' => 'b', 'c' => 'd'})
138
+ end
139
+ end
140
+
141
+ it 'coerces hash when non valid arg is given' do
142
+ invalid_args = [
143
+ 'not a hash',
144
+ ['1', '2', '3'],
145
+ 999.99
146
+ ]
147
+
148
+ invalid_args.each do |arg|
149
+ get('/coerce/hash', arg: arg) do |response|
150
+ expect(response.status).to eql 200
151
+ parsed_body = JSON.parse(response.body)
152
+ expect(parsed_body['arg']).to be_an(Hash)
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ describe 'Boolean' do
159
+ it 'coerces truthy booleans to true' do
160
+ %w(1 true t yes y).each do |bool|
161
+ get('/coerce/boolean', arg: bool) do |response|
162
+ expect(response.status).to eql 200
163
+ expect(JSON.parse(response.body)['arg']).to be true
164
+ end
165
+ end
166
+ end
167
+
168
+ it 'coerces falsey booleans to false' do
169
+ %w(0 false f no n).each do |bool|
170
+ get('/coerce/boolean', arg: bool) do |response|
171
+ expect(response.status).to eql 200
172
+ expect(JSON.parse(response.body)['arg']).to be false
173
+ expect(JSON.parse(response.body)['arg']).to_not be_nil
174
+ end
175
+ end
176
+ end
177
+
178
+ it 'returns the default boolean false value' do
179
+ get('/default/boolean/false') do |response|
180
+ expect(response.status).to eql 200
181
+ expect(JSON.parse(response.body)['arg']).to be false
182
+ end
183
+ end
184
+
185
+ it 'returns the default boolean true value' do
186
+ get('/default/boolean/true') do |response|
187
+ expect(response.status).to eql 200
188
+ expect(JSON.parse(response.body)['arg']).to be true
189
+ end
190
+ end
191
+
192
+ it 'coerces truthy booleans to true when default is false' do
193
+ %w(1 true t yes y).each do |bool|
194
+ get('/default/boolean/false', arg: bool) do |response|
195
+ expect(response.status).to eql 200
196
+ expect(JSON.parse(response.body)['arg']).to be true
197
+ end
198
+ end
199
+ end
200
+
201
+ it 'coerces falsey booleans to false when default is true' do
202
+ %w(0 false f no n).each do |bool|
203
+ get('/default/boolean/true', arg: bool) do |response|
204
+ expect(response.status).to eql 200
205
+ expect(JSON.parse(response.body)['arg']).to be false
206
+ expect(JSON.parse(response.body)['arg']).to_not be_nil
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end