haveapi 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +11 -0
- data/Rakefile +1 -0
- data/haveapi.gemspec +1 -1
- data/lib/haveapi/authentication/chain.rb +4 -0
- data/lib/haveapi/hooks.rb +68 -11
- data/lib/haveapi/model_adapters/active_record.rb +1 -1
- data/lib/haveapi/{params/param.rb → parameters/typed.rb} +4 -1
- data/lib/haveapi/params.rb +2 -2
- data/lib/haveapi/spec/api_builder.rb +75 -0
- data/lib/haveapi/spec/api_response.rb +41 -0
- data/lib/haveapi/spec/helpers.rb +5 -99
- data/lib/haveapi/spec/mock_action.rb +32 -0
- data/lib/haveapi/spec/spec_methods.rb +121 -0
- data/lib/haveapi/version.rb +1 -1
- data/lib/haveapi/views/main_layout.erb +3 -1
- data/lib/haveapi.rb +1 -1
- data/spec/action/dsl_spec.rb +199 -0
- data/spec/authorization_spec.rb +113 -0
- data/spec/common_spec.rb +47 -0
- data/spec/documentation_spec.rb +29 -0
- data/spec/envelope_spec.rb +33 -0
- data/spec/hooks_spec.rb +146 -0
- data/spec/parameters/typed_spec.rb +93 -0
- data/spec/params_spec.rb +190 -0
- data/spec/resource_spec.rb +63 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/validators/acceptance_spec.rb +29 -0
- data/spec/validators/confirmation_spec.rb +46 -0
- data/spec/validators/custom_spec.rb +6 -0
- data/spec/validators/exclusion_spec.rb +32 -0
- data/spec/validators/format_spec.rb +54 -0
- data/spec/validators/inclusion_spec.rb +43 -0
- data/spec/validators/length_spec.rb +45 -0
- data/spec/validators/numericality_spec.rb +70 -0
- data/spec/validators/presence_spec.rb +47 -0
- metadata +27 -4
- /data/lib/haveapi/{params → parameters}/resource.rb +0 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
describe HaveAPI::Action do
|
2
|
+
context 'DSL' do
|
3
|
+
it 'inherits input' do
|
4
|
+
class Resource < HaveAPI::Resource
|
5
|
+
class InputAction < HaveAPI::Action
|
6
|
+
input do
|
7
|
+
string :param
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class SubInputAction < InputAction ; end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Invokes execution of input/output blocks
|
15
|
+
Resource.routes
|
16
|
+
expect(Resource::SubInputAction.input.params.first.name).to eq(:param)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'inherits output' do
|
20
|
+
class Resource < HaveAPI::Resource
|
21
|
+
class OutputAction < HaveAPI::Action
|
22
|
+
output do
|
23
|
+
string :param
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class SubOutputAction < OutputAction ; end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Invokes execution of input/output blocks
|
31
|
+
Resource.routes
|
32
|
+
expect(Resource::SubOutputAction.output.params.first.name).to eq(:param)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'chains input' do
|
36
|
+
class Resource < HaveAPI::Resource
|
37
|
+
class InputChainAction < HaveAPI::Action
|
38
|
+
input do
|
39
|
+
string :param1
|
40
|
+
end
|
41
|
+
|
42
|
+
input do
|
43
|
+
string :param2
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Invokes execution of input/output blocks
|
49
|
+
Resource.routes
|
50
|
+
|
51
|
+
params = Resource::InputChainAction.input.params.map { |p| p.name }
|
52
|
+
expect(params).to contain_exactly(:param1, :param2)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'chains output' do
|
56
|
+
class Resource < HaveAPI::Resource
|
57
|
+
class OutputChainAction < HaveAPI::Action
|
58
|
+
output do
|
59
|
+
string :param1
|
60
|
+
end
|
61
|
+
|
62
|
+
output do
|
63
|
+
string :param2
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Invokes execution of input/output blocks
|
69
|
+
Resource.routes
|
70
|
+
|
71
|
+
params = Resource::OutputChainAction.output.params.map { |p| p.name }
|
72
|
+
expect(params).to contain_exactly(:param1, :param2)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'can combine chaining and inheritance' do
|
76
|
+
class Resource < HaveAPI::Resource
|
77
|
+
class BaseAction < HaveAPI::Action
|
78
|
+
input do
|
79
|
+
string :inbase1
|
80
|
+
end
|
81
|
+
|
82
|
+
input do
|
83
|
+
string :inbase2
|
84
|
+
end
|
85
|
+
|
86
|
+
output do
|
87
|
+
string :outbase1
|
88
|
+
end
|
89
|
+
|
90
|
+
output do
|
91
|
+
string :outbase2
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class SubAction < BaseAction
|
96
|
+
input do
|
97
|
+
string :insub1
|
98
|
+
string :insub2
|
99
|
+
end
|
100
|
+
|
101
|
+
input do
|
102
|
+
string :insub3
|
103
|
+
end
|
104
|
+
|
105
|
+
output do
|
106
|
+
string :outsub1
|
107
|
+
string :outsub2
|
108
|
+
end
|
109
|
+
|
110
|
+
output do
|
111
|
+
string :outsub3
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Invokes execution of input/output blocks
|
117
|
+
Resource.routes
|
118
|
+
|
119
|
+
input = Resource::SubAction.input.params.map { |p| p.name }
|
120
|
+
output = Resource::SubAction.output.params.map { |p| p.name }
|
121
|
+
|
122
|
+
expect(input).to contain_exactly(*%i(inbase1 inbase2 insub1 insub2 insub3))
|
123
|
+
expect(output).to contain_exactly(*%i(outbase1 outbase2 outsub1 outsub2 outsub3))
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'sets layout' do
|
127
|
+
class Resource < HaveAPI::Resource
|
128
|
+
class DefaultLayoutAction < HaveAPI::Action ; end
|
129
|
+
|
130
|
+
class ObjectLayoutAction < HaveAPI::Action
|
131
|
+
input(:object) {}
|
132
|
+
output(:object) {}
|
133
|
+
end
|
134
|
+
|
135
|
+
class ObjectListLayoutAction < HaveAPI::Action
|
136
|
+
input(:object_list) {}
|
137
|
+
output(:object_list) {}
|
138
|
+
end
|
139
|
+
|
140
|
+
class HashLayoutAction < HaveAPI::Action
|
141
|
+
input(:hash) {}
|
142
|
+
output(:hash) {}
|
143
|
+
end
|
144
|
+
|
145
|
+
class HashListLayoutAction < HaveAPI::Action
|
146
|
+
input(:hash_list) {}
|
147
|
+
output(:hash_list) {}
|
148
|
+
end
|
149
|
+
|
150
|
+
class CombinedLayoutAction < HaveAPI::Action
|
151
|
+
input(:hash) {}
|
152
|
+
output(:object_list) {}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
expect(Resource::DefaultLayoutAction.input.layout).to eq(:object)
|
157
|
+
expect(Resource::DefaultLayoutAction.output.layout).to eq(:object)
|
158
|
+
|
159
|
+
expect(Resource::ObjectLayoutAction.input.layout).to eq(:object)
|
160
|
+
expect(Resource::ObjectLayoutAction.output.layout).to eq(:object)
|
161
|
+
|
162
|
+
expect(Resource::ObjectListLayoutAction.input.layout).to eq(:object_list)
|
163
|
+
expect(Resource::ObjectListLayoutAction.output.layout).to eq(:object_list)
|
164
|
+
|
165
|
+
expect(Resource::HashLayoutAction.input.layout).to eq(:hash)
|
166
|
+
expect(Resource::HashLayoutAction.output.layout).to eq(:hash)
|
167
|
+
|
168
|
+
expect(Resource::HashListLayoutAction.input.layout).to eq(:hash_list)
|
169
|
+
expect(Resource::HashListLayoutAction.output.layout).to eq(:hash_list)
|
170
|
+
|
171
|
+
expect(Resource::CombinedLayoutAction.input.layout).to eq(:hash)
|
172
|
+
expect(Resource::CombinedLayoutAction.output.layout).to eq(:object_list)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'catches exceptions in input' do
|
176
|
+
class ExResourceIn < HaveAPI::Resource
|
177
|
+
class ExInputAction < HaveAPI::Action
|
178
|
+
input do
|
179
|
+
fail 'this is terrible!'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
expect { ExResourceIn.routes }.to raise_error(HaveAPI::BuildError)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'catches exceptions in output' do
|
188
|
+
class ExResourceOut < HaveAPI::Resource
|
189
|
+
class ExOutputAction < HaveAPI::Action
|
190
|
+
output do
|
191
|
+
fail 'this is terrible!'
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
expect { ExResourceOut.routes }.to raise_error(HaveAPI::BuildError)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
describe HaveAPI::Authorization do
|
2
|
+
class Resource < HaveAPI::Resource
|
3
|
+
class Index < HaveAPI::Actions::Default::Index
|
4
|
+
input do
|
5
|
+
string :param1
|
6
|
+
string :param2
|
7
|
+
end
|
8
|
+
|
9
|
+
output do
|
10
|
+
string :param1
|
11
|
+
string :param2
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
routes
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'defaults to deny' do
|
19
|
+
auth = HaveAPI::Authorization.new {}
|
20
|
+
expect(auth.authorized?(nil)).to be false
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'can authorize' do
|
24
|
+
auth = HaveAPI::Authorization.new { allow }
|
25
|
+
expect(auth.authorized?(nil)).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'applies restrictions' do
|
29
|
+
auth = HaveAPI::Authorization.new do
|
30
|
+
restrict filter: true
|
31
|
+
allow
|
32
|
+
end
|
33
|
+
|
34
|
+
expect(auth.authorized?(nil)).to be true
|
35
|
+
expect(auth.restrictions[:filter]).to be true
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'whitelists input' do
|
39
|
+
auth = HaveAPI::Authorization.new do
|
40
|
+
input whitelist: %i(param1)
|
41
|
+
allow
|
42
|
+
end
|
43
|
+
|
44
|
+
expect(auth.authorized?(nil)).to be true
|
45
|
+
|
46
|
+
action = Resource::Index
|
47
|
+
|
48
|
+
expect(auth.filter_input(
|
49
|
+
action.input.params,
|
50
|
+
action.model_adapter(action.input.layout).input({
|
51
|
+
param1: '123',
|
52
|
+
param2: '456',
|
53
|
+
})
|
54
|
+
).keys).to contain_exactly(:param1)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'blacklists input' do
|
58
|
+
auth = HaveAPI::Authorization.new do
|
59
|
+
input blacklist: %i(param1)
|
60
|
+
allow
|
61
|
+
end
|
62
|
+
|
63
|
+
expect(auth.authorized?(nil)).to be true
|
64
|
+
|
65
|
+
action = Resource::Index
|
66
|
+
|
67
|
+
expect(auth.filter_input(
|
68
|
+
action.input.params,
|
69
|
+
action.model_adapter(action.input.layout).input({
|
70
|
+
param1: '123',
|
71
|
+
param2: '456',
|
72
|
+
})
|
73
|
+
).keys).to contain_exactly(:param2)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'whitelists output' do
|
77
|
+
auth = HaveAPI::Authorization.new do
|
78
|
+
output whitelist: %i(param1)
|
79
|
+
allow
|
80
|
+
end
|
81
|
+
|
82
|
+
expect(auth.authorized?(nil)).to be true
|
83
|
+
|
84
|
+
action = Resource::Index
|
85
|
+
|
86
|
+
expect(auth.filter_output(
|
87
|
+
action.output.params,
|
88
|
+
action.model_adapter(action.output.layout).output(nil, {
|
89
|
+
param1: '123',
|
90
|
+
param2: '456',
|
91
|
+
})
|
92
|
+
).keys).to contain_exactly(:param1)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'blacklists output' do
|
96
|
+
auth = HaveAPI::Authorization.new do
|
97
|
+
output blacklist: %i(param1)
|
98
|
+
allow
|
99
|
+
end
|
100
|
+
|
101
|
+
expect(auth.authorized?(nil)).to be true
|
102
|
+
|
103
|
+
action = Resource::Index
|
104
|
+
|
105
|
+
expect(auth.filter_output(
|
106
|
+
action.output.params,
|
107
|
+
action.model_adapter(action.output.layout).output(nil, {
|
108
|
+
param1: '123',
|
109
|
+
param2: '456',
|
110
|
+
})
|
111
|
+
).keys).to contain_exactly(:param2)
|
112
|
+
end
|
113
|
+
end
|
data/spec/common_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
describe HaveAPI::Common do
|
2
|
+
class Test1 < HaveAPI::Common
|
3
|
+
has_attr :attr1
|
4
|
+
has_attr :attr2, 42
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'defines attributes' do
|
8
|
+
expect(Test1.attr1).to be_nil
|
9
|
+
expect(Test1.attr2).to eq(42)
|
10
|
+
end
|
11
|
+
|
12
|
+
class Test2 < HaveAPI::Common
|
13
|
+
has_attr :attr1
|
14
|
+
has_attr :attr2, 42
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'sets attributes' do
|
18
|
+
Test2.attr1 'val1'
|
19
|
+
Test2.attr2 663
|
20
|
+
|
21
|
+
expect(Test2.attr1).to eq('val1')
|
22
|
+
expect(Test2.attr2).to eq(663)
|
23
|
+
end
|
24
|
+
|
25
|
+
class Test3 < HaveAPI::Common
|
26
|
+
has_attr :attr1
|
27
|
+
has_attr :attr2, 42
|
28
|
+
has_attr :attr3
|
29
|
+
|
30
|
+
attr1 'foo'
|
31
|
+
attr2 :bar
|
32
|
+
|
33
|
+
def self.inherited(subclass)
|
34
|
+
inherit_attrs(subclass)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class SubTest3 < Test3
|
39
|
+
attr3 'bar'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'inherites attributes' do
|
43
|
+
expect(SubTest3.attr1).to eq('foo')
|
44
|
+
expect(SubTest3.attr2).to eq(:bar)
|
45
|
+
expect(SubTest3.attr3).to eq('bar')
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
describe 'Documentation' do
|
2
|
+
it 'responds to OPTIONS /' do
|
3
|
+
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'responds to OPTIONS /?describe=versions' do
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'responds to OPTIONS /?describe=default' do
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'responds to OPTIONS /<version>' do
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'responds to OPTIONS /<every action>?method=<method>' do
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'has online doc' do
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'has online doc for every version' do
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
describe 'Envelope' do
|
2
|
+
context 'documentation' do
|
3
|
+
empty_api
|
4
|
+
|
5
|
+
it 'returns correct envelope' do
|
6
|
+
call_api(:options, '/')
|
7
|
+
expect(api_response.envelope.keys).to contain_exactly(
|
8
|
+
*%i(version status response message errors)
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'succeeds' do
|
13
|
+
call_api(:options, '/')
|
14
|
+
expect(api_response).to be_ok
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'data' do
|
19
|
+
empty_api
|
20
|
+
|
21
|
+
it 'returns correct envelope' do
|
22
|
+
call_api(:get, '/unknown_resource')
|
23
|
+
expect(api_response.envelope.keys).to contain_exactly(
|
24
|
+
*%i(status response message errors)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'fails' do
|
29
|
+
call_api(:get, '/unknown_resource')
|
30
|
+
expect(api_response).to_not be_ok
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/hooks_spec.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
describe HaveAPI::Hooks do
|
2
|
+
class ClassLevel
|
3
|
+
include HaveAPI::Hookable
|
4
|
+
|
5
|
+
has_hook :simple_hook
|
6
|
+
has_hook :arg_hook
|
7
|
+
has_hook :ret_hook
|
8
|
+
has_hook :context_hook
|
9
|
+
end
|
10
|
+
|
11
|
+
class InstanceLevel
|
12
|
+
include HaveAPI::Hookable
|
13
|
+
|
14
|
+
has_hook :simple_hook
|
15
|
+
has_hook :arg_hook
|
16
|
+
has_hook :ret_hook
|
17
|
+
has_hook :context_hook
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect_hook(name, &block)
|
21
|
+
@obj.connect_hook(name, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def call_hooks(*args)
|
25
|
+
case @level
|
26
|
+
when :class
|
27
|
+
@obj.call_hooks(*args)
|
28
|
+
|
29
|
+
when :instance
|
30
|
+
if @method
|
31
|
+
@obj.method(@method).call(*args)
|
32
|
+
|
33
|
+
else
|
34
|
+
@obj.call_hooks_for(*args)
|
35
|
+
end
|
36
|
+
|
37
|
+
else
|
38
|
+
fail "unknown level '#{@level}'"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
shared_examples(:common) do
|
43
|
+
it 'calls hooks' do
|
44
|
+
called = false
|
45
|
+
|
46
|
+
connect_hook(:simple_hook) do |ret|
|
47
|
+
called = true
|
48
|
+
ret
|
49
|
+
end
|
50
|
+
|
51
|
+
call_hooks(:simple_hook)
|
52
|
+
expect(called).to be true
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'passes arguments' do
|
56
|
+
called = false
|
57
|
+
|
58
|
+
connect_hook(:arg_hook) do |ret, a, b, c|
|
59
|
+
called = true
|
60
|
+
expect([a, b, c]).to eq([1, 2, 3])
|
61
|
+
ret
|
62
|
+
end
|
63
|
+
|
64
|
+
call_hooks(:arg_hook, args: [1, 2, 3])
|
65
|
+
expect(called).to be true
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'chains hooks' do
|
69
|
+
arr = []
|
70
|
+
|
71
|
+
5.times do |i|
|
72
|
+
connect_hook(:simple_hook) do |ret|
|
73
|
+
arr << i
|
74
|
+
ret
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
call_hooks(:simple_hook)
|
79
|
+
expect(arr).to eq([0, 1, 2, 3, 4])
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'chains return value' do
|
83
|
+
5.times do
|
84
|
+
connect_hook(:ret_hook) do |ret|
|
85
|
+
ret[:counter] += 1
|
86
|
+
ret
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
sum = call_hooks(:ret_hook, initial: {counter: 0})
|
91
|
+
expect(sum[:counter]).to eq(5)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'executes block in given context' do
|
95
|
+
class CustomEnv
|
96
|
+
def foo
|
97
|
+
'bar'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
connect_hook(:context_hook) do |ret|
|
102
|
+
ret[:val] = foo
|
103
|
+
ret
|
104
|
+
end
|
105
|
+
|
106
|
+
res = call_hooks(:context_hook, CustomEnv.new)
|
107
|
+
expect(res[:val]).to eq('bar')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'on class level' do
|
112
|
+
before(:each) do
|
113
|
+
@obj = ClassLevel
|
114
|
+
@level = :class
|
115
|
+
end
|
116
|
+
|
117
|
+
include_examples :common
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'on instance level' do
|
121
|
+
context 'all hooks' do
|
122
|
+
before(:each) do
|
123
|
+
@obj = InstanceLevel.new
|
124
|
+
@level = :instance
|
125
|
+
end
|
126
|
+
|
127
|
+
include_examples :common
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'only class hooks' do
|
131
|
+
# FIXME: class hooks fail (that is correct, no class hooks are defined)
|
132
|
+
# must find a way to test failure
|
133
|
+
#include_examples :common
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'only instance hooks' do
|
137
|
+
before(:each) do
|
138
|
+
@obj = InstanceLevel.new
|
139
|
+
@level = :instance
|
140
|
+
@method = :call_instance_hooks_for
|
141
|
+
end
|
142
|
+
|
143
|
+
include_examples :common
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
describe 'Parameters::Typed' do
|
4
|
+
def p_type(type)
|
5
|
+
HaveAPI::Parameters::Typed.new(:param1, type: type)
|
6
|
+
end
|
7
|
+
|
8
|
+
def p_arg(arg = {})
|
9
|
+
HaveAPI::Parameters::Typed.new(*[:param1, arg])
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'does not change provided arguments' do
|
13
|
+
kwargs = {
|
14
|
+
label: 'Param 1',
|
15
|
+
desc: 'Desc',
|
16
|
+
required: true,
|
17
|
+
}
|
18
|
+
p_arg(kwargs)
|
19
|
+
expect(kwargs.keys).to contain_exactly(*%i(label desc required))
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'automatically sets label' do
|
23
|
+
p = p_arg
|
24
|
+
expect(p.label).to eq('Param1')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'accepts custom label' do
|
28
|
+
p = p_arg(label: 'Custom')
|
29
|
+
expect(p.label).to eq('Custom')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'rejects unknown parameters' do
|
33
|
+
expect do
|
34
|
+
p_arg(shiny: true)
|
35
|
+
end.to raise_error(RuntimeError)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'can be required' do
|
39
|
+
p = p_arg(required: true)
|
40
|
+
expect(p.required?).to be true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'can be optional' do
|
44
|
+
p = p_arg
|
45
|
+
expect(p.optional?).to be true
|
46
|
+
|
47
|
+
p = p_arg(required: false)
|
48
|
+
expect(p.optional?).to be true
|
49
|
+
|
50
|
+
p = p_arg(required: nil)
|
51
|
+
expect(p.optional?).to be true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'cleans input value' do
|
55
|
+
# Integer
|
56
|
+
p = p_type(Integer)
|
57
|
+
expect(p.clean('42')).to eq(42)
|
58
|
+
|
59
|
+
# Float
|
60
|
+
p = p_type(Float)
|
61
|
+
expect(p.clean('3.1456')).to eq(3.1456)
|
62
|
+
|
63
|
+
# Boolean
|
64
|
+
p = p_type(Boolean)
|
65
|
+
|
66
|
+
%w(true t yes y 1).each do |v|
|
67
|
+
expect(p.clean(v)).to be true
|
68
|
+
end
|
69
|
+
|
70
|
+
%w(false f no n 0).each do |v|
|
71
|
+
expect(p.clean(v)).to be false
|
72
|
+
end
|
73
|
+
|
74
|
+
# Datetime
|
75
|
+
p = p_type(Datetime)
|
76
|
+
t = Time.now
|
77
|
+
t2 = Time.iso8601(t.iso8601)
|
78
|
+
|
79
|
+
expect(p.clean(t.iso8601)).to eq(t2)
|
80
|
+
expect { p.clean('bzz') }.to raise_error(HaveAPI::ValidationError)
|
81
|
+
|
82
|
+
# String, Text
|
83
|
+
p = p_type(String)
|
84
|
+
expect(p.clean('bzz')).to eq('bzz')
|
85
|
+
|
86
|
+
# Defaults
|
87
|
+
p = p_type(String)
|
88
|
+
expect(p.clean(nil)).to be_nil
|
89
|
+
|
90
|
+
p.patch(default: 'bazinga')
|
91
|
+
expect(p.clean(nil)).to eq('bazinga')
|
92
|
+
end
|
93
|
+
end
|