haveapi 0.4.2 → 0.5.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.
- 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
|