haveapi 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +11 -0
  3. data/Rakefile +1 -0
  4. data/haveapi.gemspec +1 -1
  5. data/lib/haveapi/authentication/chain.rb +4 -0
  6. data/lib/haveapi/hooks.rb +68 -11
  7. data/lib/haveapi/model_adapters/active_record.rb +1 -1
  8. data/lib/haveapi/{params/param.rb → parameters/typed.rb} +4 -1
  9. data/lib/haveapi/params.rb +2 -2
  10. data/lib/haveapi/spec/api_builder.rb +75 -0
  11. data/lib/haveapi/spec/api_response.rb +41 -0
  12. data/lib/haveapi/spec/helpers.rb +5 -99
  13. data/lib/haveapi/spec/mock_action.rb +32 -0
  14. data/lib/haveapi/spec/spec_methods.rb +121 -0
  15. data/lib/haveapi/version.rb +1 -1
  16. data/lib/haveapi/views/main_layout.erb +3 -1
  17. data/lib/haveapi.rb +1 -1
  18. data/spec/action/dsl_spec.rb +199 -0
  19. data/spec/authorization_spec.rb +113 -0
  20. data/spec/common_spec.rb +47 -0
  21. data/spec/documentation_spec.rb +29 -0
  22. data/spec/envelope_spec.rb +33 -0
  23. data/spec/hooks_spec.rb +146 -0
  24. data/spec/parameters/typed_spec.rb +93 -0
  25. data/spec/params_spec.rb +190 -0
  26. data/spec/resource_spec.rb +63 -0
  27. data/spec/spec_helper.rb +21 -0
  28. data/spec/validators/acceptance_spec.rb +29 -0
  29. data/spec/validators/confirmation_spec.rb +46 -0
  30. data/spec/validators/custom_spec.rb +6 -0
  31. data/spec/validators/exclusion_spec.rb +32 -0
  32. data/spec/validators/format_spec.rb +54 -0
  33. data/spec/validators/inclusion_spec.rb +43 -0
  34. data/spec/validators/length_spec.rb +45 -0
  35. data/spec/validators/numericality_spec.rb +70 -0
  36. data/spec/validators/presence_spec.rb +47 -0
  37. metadata +27 -4
  38. /data/lib/haveapi/{params → parameters}/resource.rb +0 -0
@@ -0,0 +1,190 @@
1
+ describe HaveAPI::Params do
2
+ class MyResource < HaveAPI::Resource
3
+ params(:all) do
4
+ string :res_param1
5
+ string :res_param2
6
+ end
7
+
8
+ class Index < HaveAPI::Actions::Default::Index
9
+
10
+ end
11
+
12
+ class Show < HaveAPI::Actions::Default::Show
13
+ output do
14
+ string :not_label
15
+ end
16
+ end
17
+
18
+ class Create < HaveAPI::Actions::Default::Create
19
+
20
+ end
21
+ end
22
+
23
+ it 'executes all blocks' do
24
+ p = HaveAPI::Params.new(:input, MyResource::Index)
25
+ p.add_block Proc.new { string :param1 }
26
+ p.add_block Proc.new { string :param2 }
27
+ p.add_block Proc.new { string :param3 }
28
+ p.exec
29
+ expect(p.params.map { |p| p.name }).to contain_exactly(*%i(param1 param2 param3))
30
+ end
31
+
32
+ it 'returns deduced singular namespace' do
33
+ p = HaveAPI::Params.new(:input, MyResource::Index)
34
+ expect(p.namespace).to eq(:my_resource)
35
+ end
36
+
37
+ it 'returns deduced plural namespace' do
38
+ p = HaveAPI::Params.new(:input, MyResource::Index)
39
+ p.layout = :object_list
40
+ expect(p.namespace).to eq(:my_resources)
41
+ end
42
+
43
+ it 'returns set namespace' do
44
+ p = HaveAPI::Params.new(:input, MyResource::Index)
45
+ p.namespace = :custom_ns
46
+ expect(p.namespace).to eq(:custom_ns)
47
+ end
48
+
49
+ it 'uses params from parent resource' do
50
+ p = HaveAPI::Params.new(:input, MyResource::Index)
51
+ p.add_block Proc.new { use :all }
52
+ p.exec
53
+ expect(p.params.map { |p| p.name }).to contain_exactly(*%i(res_param1 res_param2))
54
+ end
55
+
56
+ it 'has param requires' do
57
+ p = HaveAPI::Params.new(:input, MyResource::Index)
58
+ p.add_block Proc.new { requires :p_required }
59
+ p.exec
60
+ expect(p.params.first.required?).to be true
61
+ end
62
+
63
+ it 'has param optional' do
64
+ p = HaveAPI::Params.new(:input, MyResource::Index)
65
+ p.add_block Proc.new { optional :p_optional }
66
+ p.exec
67
+ expect(p.params.first.required?).to be false
68
+ end
69
+
70
+ it 'has param string' do
71
+ p = HaveAPI::Params.new(:input, MyResource::Index)
72
+ p.add_block Proc.new { string :p_string }
73
+ p.exec
74
+ expect(p.params.first.type).to eq(String)
75
+ end
76
+
77
+ it 'has param text' do
78
+ p = HaveAPI::Params.new(:input, MyResource::Index)
79
+ p.add_block Proc.new { text :p_text }
80
+ p.exec
81
+ expect(p.params.first.type).to eq(Text)
82
+ end
83
+
84
+ %i(id integer foreign_key).each do |type|
85
+ it "has param #{type}" do
86
+ p = HaveAPI::Params.new(:input, MyResource::Index)
87
+ p.add_block Proc.new { send(type, :"p_#{type}") }
88
+ p.exec
89
+ expect(p.params.first.type).to eq(Integer)
90
+ end
91
+ end
92
+
93
+ it 'has param float' do
94
+ p = HaveAPI::Params.new(:input, MyResource::Index)
95
+ p.add_block Proc.new { float :p_float }
96
+ p.exec
97
+ expect(p.params.first.type).to eq(Float)
98
+ end
99
+
100
+ it 'has param bool' do
101
+ p = HaveAPI::Params.new(:input, MyResource::Index)
102
+ p.add_block Proc.new { bool :p_bool }
103
+ p.exec
104
+ expect(p.params.first.type).to eq(Boolean)
105
+ end
106
+
107
+ it 'has param datetime' do
108
+ p = HaveAPI::Params.new(:input, MyResource::Index)
109
+ p.add_block Proc.new { datetime :p_datetime }
110
+ p.exec
111
+ expect(p.params.first.type).to eq(Datetime)
112
+ end
113
+
114
+ it 'has param param' do
115
+ p = HaveAPI::Params.new(:input, MyResource::Index)
116
+ p.add_block Proc.new { param :p_param, type: Integer }
117
+ p.exec
118
+ expect(p.params.first.type).to eq(Integer)
119
+ end
120
+
121
+ it 'has param resource' do
122
+ p = HaveAPI::Params.new(:input, MyResource::Index)
123
+ p.add_block Proc.new { resource MyResource }
124
+ p.exec
125
+ expect(p.params.first).to be_an_instance_of(HaveAPI::Parameters::Resource)
126
+ end
127
+
128
+ it 'patches params' do
129
+ p = HaveAPI::Params.new(:input, MyResource::Index)
130
+ p.add_block(Proc.new do
131
+ string :param1, label: 'Param 1'
132
+ string :param2, label: 'Param 2', desc: 'Implicit description'
133
+ end)
134
+ p.exec
135
+ p.patch(:param1, label: 'Better param 1')
136
+ p.patch(:param2, desc: 'Better description')
137
+ expect(p.params.first.label).to eq('Better param 1')
138
+ expect(p.params.second.desc).to eq('Better description')
139
+ end
140
+
141
+ it 'validates upon build' do
142
+ p = HaveAPI::Params.new(:output, MyResource::Index)
143
+ p.add_block Proc.new { resource MyResource }
144
+ p.exec
145
+ expect(p.params.first).to be_an_instance_of(HaveAPI::Parameters::Resource)
146
+ expect { p.validate_build }.to raise_error(RuntimeError)
147
+ end
148
+
149
+ it 'accepts valid input layout' do
150
+ p = HaveAPI::Params.new(:input, MyResource::Index)
151
+ p.add_block(Proc.new do
152
+ string :param1, required: true
153
+ string :param2
154
+ end)
155
+ p.exec
156
+
157
+ expect do
158
+ p.check_layout({
159
+ my_resource: {}
160
+ })
161
+ end.not_to raise_error
162
+ end
163
+
164
+ it 'rejects invalid input layout' do
165
+ p = HaveAPI::Params.new(:input, MyResource::Index)
166
+ p.add_block(Proc.new do
167
+ string :param1, required: true
168
+ string :param2
169
+ end)
170
+ p.exec
171
+
172
+ expect do
173
+ p.check_layout({
174
+ something_bad: {}
175
+ })
176
+ end.to raise_error(HaveAPI::ValidationError)
177
+ end
178
+
179
+ it 'indexes parameters by name' do
180
+ p = HaveAPI::Params.new(:input, MyResource::Index)
181
+ p.add_block(Proc.new do
182
+ string :param1
183
+ string :param2
184
+ end)
185
+ p.exec
186
+
187
+ expect(p[:param1]).to eq(p.params.first)
188
+ expect(p[:param2]).to eq(p.params.second)
189
+ end
190
+ end
@@ -0,0 +1,63 @@
1
+ describe HaveAPI::Resource do
2
+ class PluralTest < HaveAPI::Resource
3
+
4
+ end
5
+
6
+ class SingularTest < HaveAPI::Resource
7
+ singular true
8
+ end
9
+
10
+ it 'has correct obj_type' do
11
+ expect(PluralTest.obj_type).to eq(:resource)
12
+ expect(SingularTest.obj_type).to eq(:resource)
13
+ end
14
+
15
+ it 'has plural name' do
16
+ expect(PluralTest.resource_name).to eq('plural_tests')
17
+ end
18
+
19
+ it 'has singular name' do
20
+ expect(SingularTest.resource_name).to eq('singular_test')
21
+ end
22
+
23
+ class ComplexTest < HaveAPI::Resource
24
+ class Index < HaveAPI::Actions::Default::Index ; end
25
+ class Show < HaveAPI::Actions::Default::Show ; end
26
+ class Create < HaveAPI::Actions::Default::Create ; end
27
+ class Dummy ; end
28
+
29
+ class SubResource < HaveAPI::Resource
30
+ class Index < HaveAPI::Actions::Default::Index ; end
31
+ class Show < HaveAPI::Actions::Default::Show ; end
32
+ end
33
+ end
34
+
35
+ it 'iterates over actions' do
36
+ actions = []
37
+
38
+ ComplexTest.actions do |a|
39
+ actions << a
40
+ end
41
+
42
+ expect(actions).to contain_exactly(
43
+ ComplexTest::Index,
44
+ ComplexTest::Show,
45
+ ComplexTest::Create
46
+ )
47
+ end
48
+
49
+ it 'iterates over resources' do
50
+ resources = []
51
+
52
+ ComplexTest.resources do |r|
53
+ resources << r
54
+ end
55
+
56
+ expect(resources).to contain_exactly(ComplexTest::SubResource)
57
+ end
58
+
59
+ it 'defines and returns resource-wide params' do
60
+ ComplexTest.params(:name) { 'executed' }
61
+ expect(ComplexTest.params(:name).call).to eq('executed')
62
+ end
63
+ end
@@ -0,0 +1,21 @@
1
+ require 'require_all'
2
+ require_relative '../lib/haveapi'
3
+ require_rel '../lib/haveapi/spec/*.rb'
4
+
5
+ module HaveAPI
6
+ module Spec
7
+ module API
8
+
9
+ end
10
+ end
11
+ end
12
+
13
+ require_rel 'api'
14
+
15
+ # Configure specs
16
+ RSpec.configure do |config|
17
+ config.order = 'random'
18
+
19
+ config.extend HaveAPI::Spec::ApiBuilder
20
+ config.include HaveAPI::Spec::SpecMethods
21
+ end
@@ -0,0 +1,29 @@
1
+ describe HaveAPI::Validators::Acceptance do
2
+ shared_examples(:all) do
3
+ it 'accepts correct value' do
4
+ expect(@v.valid?('foo')).to be true
5
+ end
6
+
7
+ it "rejects incorrect value" do
8
+ expect(@v.valid?('bar')).to be false
9
+ end
10
+ end
11
+
12
+ context 'short form' do
13
+ before(:each) do
14
+ @v = HaveAPI::Validators::Acceptance.new(:accept, 'foo')
15
+ end
16
+
17
+ include_examples :all
18
+ end
19
+
20
+ context 'full form' do
21
+ before(:each) do
22
+ @v = HaveAPI::Validators::Acceptance.new(:accept, {
23
+ value: 'foo'
24
+ })
25
+ end
26
+
27
+ include_examples :all
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ describe HaveAPI::Validators::Confirmation do
2
+ shared_examples(:all) do
3
+ it 'accepts the same value' do
4
+ expect(@v.validate('foo', {other_param: 'foo'})).to be true
5
+ end
6
+
7
+ it "rejects a different value" do
8
+ expect(@v.validate('bar', {other_param: 'foo'})).to be false
9
+ end
10
+ end
11
+
12
+ context 'short form' do
13
+ before(:each) do
14
+ @v = HaveAPI::Validators::Confirmation.new(:confirm, :other_param)
15
+ end
16
+
17
+ include_examples :all
18
+ end
19
+
20
+ context 'full form' do
21
+ before(:each) do
22
+ @v = HaveAPI::Validators::Confirmation.new(:confirm, {
23
+ param: :other_param
24
+ })
25
+ end
26
+
27
+ include_examples :all
28
+ end
29
+
30
+ context 'with equal = false' do
31
+ before(:each) do
32
+ @v = HaveAPI::Validators::Confirmation.new(:confirm, {
33
+ param: :other_param,
34
+ equal: false
35
+ })
36
+ end
37
+
38
+ it 'rejects the same value' do
39
+ expect(@v.validate('foo', {other_param: 'foo'})).to be false
40
+ end
41
+
42
+ it 'accepts a different value' do
43
+ expect(@v.validate('bar', {other_param: 'foo'})).to be true
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,6 @@
1
+ describe HaveAPI::Validators::Custom do
2
+ it 'always passes' do
3
+ v = HaveAPI::Validators::Custom.new(:validate, 'some custom validation')
4
+ expect(v.valid?('WHATEVER')).to be true
5
+ end
6
+ end
@@ -0,0 +1,32 @@
1
+ describe HaveAPI::Validators::Exclusion do
2
+ shared_examples(:all) do
3
+ it 'rejects a listed value' do
4
+ expect(@v.valid?('one')).to be false
5
+ expect(@v.valid?('two')).to be false
6
+ expect(@v.valid?('three')).to be false
7
+ end
8
+
9
+ it "accepts an unlisted value" do
10
+ expect(@v.valid?('zero')).to be true
11
+ expect(@v.valid?('four')).to be true
12
+ end
13
+ end
14
+
15
+ context 'short form' do
16
+ before(:each) do
17
+ @v = HaveAPI::Validators::Exclusion.new(:exclude, %w(one two three))
18
+ end
19
+
20
+ include_examples :all
21
+ end
22
+
23
+ context 'full form' do
24
+ before(:each) do
25
+ @v = HaveAPI::Validators::Exclusion.new(:exclude, {
26
+ values: %w(one two three)
27
+ })
28
+ end
29
+
30
+ include_examples :all
31
+ end
32
+ end
@@ -0,0 +1,54 @@
1
+ describe HaveAPI::Validators::Format do
2
+ shared_examples(:all) do
3
+ it 'accepts a value that matches the regexp' do
4
+ expect(@v.valid?('aab')).to be true
5
+ expect(@v.valid?('aacacb')).to be true
6
+ end
7
+
8
+ it "rejects a value that does not match the regexp" do
9
+ expect(@v.valid?('aacac')).to be false
10
+ expect(@v.valid?('bacacb')).to be false
11
+ expect(@v.valid?('b')).to be false
12
+ end
13
+ end
14
+
15
+ context 'with match = true' do
16
+ context 'short form' do
17
+ before(:each) do
18
+ @v = HaveAPI::Validators::Format.new(:format, /^a[^b]+b$/)
19
+ end
20
+
21
+ include_examples :all
22
+ end
23
+
24
+ context 'full form' do
25
+ before(:each) do
26
+ @v = HaveAPI::Validators::Format.new(:format, {
27
+ rx: /^a[^b]+b$/
28
+ })
29
+ end
30
+
31
+ include_examples :all
32
+ end
33
+ end
34
+
35
+ context 'with match = false' do
36
+ before(:each) do
37
+ @v = HaveAPI::Validators::Format.new(:format, {
38
+ rx: /^a[^b]+b$/,
39
+ match: false
40
+ })
41
+ end
42
+
43
+ it 'rejects a value that matches the regexp' do
44
+ expect(@v.valid?('aab')).to be false
45
+ expect(@v.valid?('aacacb')).to be false
46
+ end
47
+
48
+ it "accepts a value if it does not match the regexp" do
49
+ expect(@v.valid?('aacac')).to be true
50
+ expect(@v.valid?('bacacb')).to be true
51
+ expect(@v.valid?('b')).to be true
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,43 @@
1
+ describe HaveAPI::Validators::Inclusion do
2
+ shared_examples(:all) do
3
+ it 'accepts a listed value' do
4
+ expect(@v.valid?('one')).to be true
5
+ expect(@v.valid?('two')).to be true
6
+ expect(@v.valid?('three')).to be true
7
+ end
8
+
9
+ it "rejects an unlisted value" do
10
+ expect(@v.valid?('zero')).to be false
11
+ expect(@v.valid?('four')).to be false
12
+ end
13
+ end
14
+
15
+ [
16
+ %w(one two three),
17
+ {
18
+ one: 'Fancy one',
19
+ two: 'Fancy two',
20
+ three: 'Fancy three'
21
+ }
22
+ ].each do |include|
23
+ context "with include as a '#{include.class}'" do
24
+ context 'short form' do
25
+ before(:each) do
26
+ @v = HaveAPI::Validators::Inclusion.new(:include, %w(one two three))
27
+ end
28
+
29
+ include_examples :all
30
+ end
31
+
32
+ context 'full form' do
33
+ before(:each) do
34
+ @v = HaveAPI::Validators::Inclusion.new(:include, {
35
+ values: %w(one two three)
36
+ })
37
+ end
38
+
39
+ include_examples :all
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,45 @@
1
+ describe HaveAPI::Validators::Length do
2
+ it 'does not allow to mix min/max with equals' do
3
+ expect do
4
+ HaveAPI::Validators::Length.new(:length, {min: 33, equals: 42})
5
+ end.to raise_error(RuntimeError)
6
+ end
7
+
8
+ it 'requires one of min, max or equals' do
9
+ expect do
10
+ HaveAPI::Validators::Length.new(:length, {})
11
+ end.to raise_error(RuntimeError)
12
+ end
13
+
14
+ it 'checks minimum' do
15
+ v = HaveAPI::Validators::Length.new(:length, {min: 2})
16
+ expect(v.valid?('a'*1)).to be false
17
+ expect(v.valid?('a'*2)).to be true
18
+ expect(v.valid?('a'*33)).to be true
19
+ end
20
+
21
+ it 'checks maximum' do
22
+ v = HaveAPI::Validators::Length.new(:length, {max: 5})
23
+ expect(v.valid?('a'*4)).to be true
24
+ expect(v.valid?('a'*5)).to be true
25
+ expect(v.valid?('a'*6)).to be false
26
+ expect(v.valid?('a'*11)).to be false
27
+ end
28
+
29
+ it 'checks range' do
30
+ v = HaveAPI::Validators::Length.new(:length, {min: 3, max: 6})
31
+ expect(v.valid?('a'*2)).to be false
32
+ expect(v.valid?('a'*3)).to be true
33
+ expect(v.valid?('a'*4)).to be true
34
+ expect(v.valid?('a'*5)).to be true
35
+ expect(v.valid?('a'*6)).to be true
36
+ expect(v.valid?('a'*7)).to be false
37
+ end
38
+
39
+ it 'check a specific length' do
40
+ v = HaveAPI::Validators::Length.new(:length, {equals: 4})
41
+ expect(v.valid?('a'*2)).to be false
42
+ expect(v.valid?('a'*4)).to be true
43
+ expect(v.valid?('a'*5)).to be false
44
+ end
45
+ end
@@ -0,0 +1,70 @@
1
+ describe HaveAPI::Validators::Numericality do
2
+ it 'cannot be both even and odd at the same time' do
3
+ expect do
4
+ HaveAPI::Validators::Numericality.new(:number, {odd: true, even: true})
5
+ end.to raise_error(RuntimeError)
6
+ end
7
+
8
+ it 'checks minimum' do
9
+ v = HaveAPI::Validators::Numericality.new(:number, {min: 5})
10
+ expect(v.valid?(4)).to be false
11
+ expect(v.valid?(5)).to be true
12
+ expect(v.valid?(6)).to be true
13
+ end
14
+
15
+ it 'checks maximum' do
16
+ v = HaveAPI::Validators::Numericality.new(:number, {max: 50})
17
+ expect(v.valid?(100)).to be false
18
+ expect(v.valid?(51)).to be false
19
+ expect(v.valid?(50)).to be true
20
+ expect(v.valid?(40)).to be true
21
+ end
22
+
23
+ it 'checks that x % y = 0' do
24
+ v = HaveAPI::Validators::Numericality.new(:number, {mod: 2})
25
+ expect(v.valid?(3)).to be false
26
+ expect(v.valid?(15)).to be false
27
+ expect(v.valid?(0)).to be true
28
+ expect(v.valid?(2)).to be true
29
+ expect(v.valid?(48)).to be true
30
+ end
31
+
32
+ it 'checks that the number is in a step' do
33
+ v = HaveAPI::Validators::Numericality.new(:number, {step: 3})
34
+ expect(v.valid?(4)).to be false
35
+ expect(v.valid?(14)).to be false
36
+ expect(v.valid?(0)).to be true
37
+ expect(v.valid?(3)).to be true
38
+ expect(v.valid?(6)).to be true
39
+ expect(v.valid?(9)).to be true
40
+ end
41
+
42
+ it 'checks that the number is in a step with a minimum' do
43
+ v = HaveAPI::Validators::Numericality.new(:number, {min: 5, step: 3})
44
+ expect(v.valid?(0)).to be false
45
+ expect(v.valid?(3)).to be false
46
+ expect(v.valid?(4)).to be false
47
+ expect(v.valid?(12)).to be false
48
+ expect(v.valid?(15)).to be false
49
+ expect(v.valid?(5)).to be true
50
+ expect(v.valid?(8)).to be true
51
+ expect(v.valid?(11)).to be true
52
+ expect(v.valid?(14)).to be true
53
+ end
54
+
55
+ it 'checks that the number is even' do
56
+ v = HaveAPI::Validators::Numericality.new(:number, {even: true})
57
+ expect(v.valid?(1)).to be false
58
+ expect(v.valid?(3)).to be false
59
+ expect(v.valid?(0)).to be true
60
+ expect(v.valid?(2)).to be true
61
+ end
62
+
63
+ it 'checks that the number is odd' do
64
+ v = HaveAPI::Validators::Numericality.new(:number, {odd: true})
65
+ expect(v.valid?(1)).to be true
66
+ expect(v.valid?(3)).to be true
67
+ expect(v.valid?(0)).to be false
68
+ expect(v.valid?(2)).to be false
69
+ end
70
+ end
@@ -0,0 +1,47 @@
1
+ describe HaveAPI::Validators::Presence do
2
+ shared_examples(:all) do
3
+ it 'accepts a present value' do
4
+ expect(@v.valid?('foo')).to be true
5
+ end
6
+
7
+ it 'rejects a missing or empty value' do
8
+ expect(@v.valid?(nil)).to be false
9
+ expect(@v.valid?('')).to be false
10
+ expect(@v.valid?(" \t"*4)).to be false
11
+ end
12
+ end
13
+
14
+ context 'with empty = true' do
15
+ context 'in short form' do
16
+ before(:each) do
17
+ @v = HaveAPI::Validators::Presence.new(:required, true)
18
+ end
19
+
20
+ include_examples :all
21
+ end
22
+
23
+ context 'in full form' do
24
+ before(:each) do
25
+ @v = HaveAPI::Validators::Presence.new(:required, {})
26
+ end
27
+
28
+ include_examples :all
29
+ end
30
+ end
31
+
32
+ context 'with empty = false' do
33
+ before(:each) do
34
+ @v = HaveAPI::Validators::Presence.new(:required, {empty: true})
35
+ end
36
+
37
+ it 'accepts a present value' do
38
+ expect(@v.valid?('foo')).to be true
39
+ end
40
+
41
+ it 'rejects a missing or an empty value' do
42
+ expect(@v.valid?(nil)).to be false
43
+ expect(@v.valid?('')).to be true
44
+ expect(@v.valid?(" \t"*4)).to be true
45
+ end
46
+ end
47
+ end