sinatra-param2 1.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 (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