policy 1.0.1
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 +7 -0
- data/.coveralls.yml +2 -0
- data/.metrics +5 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +18 -0
- data/.yardopts +3 -0
- data/Gemfile +7 -0
- data/Guardfile +15 -0
- data/LICENSE +21 -0
- data/README.md +223 -0
- data/Rakefile +17 -0
- data/config/metrics/STYLEGUIDE +231 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +14 -0
- data/config/metrics/pippi.yml +3 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +87 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +5 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/policy/follower/followed_policies.rb +45 -0
- data/lib/policy/follower/followed_policy.rb +104 -0
- data/lib/policy/follower/names.rb +29 -0
- data/lib/policy/follower.rb +143 -0
- data/lib/policy/interface.rb +48 -0
- data/lib/policy/validations.rb +28 -0
- data/lib/policy/version.rb +9 -0
- data/lib/policy/violation_error.rb +52 -0
- data/lib/policy.rb +40 -0
- data/policy.gemspec +23 -0
- data/spec/features/follower_spec.rb +95 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/tests/policy/follower/followed_policies_spec.rb +87 -0
- data/spec/tests/policy/follower/followed_policy_spec.rb +117 -0
- data/spec/tests/policy/follower/names_spec.rb +19 -0
- data/spec/tests/policy/follower_spec.rb +220 -0
- data/spec/tests/policy/interface_spec.rb +83 -0
- data/spec/tests/policy/validations_spec.rb +13 -0
- data/spec/tests/policy/violation_error_spec.rb +75 -0
- data/spec/tests/policy_spec.rb +35 -0
- metadata +142 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The integration test for policy follower
|
4
|
+
describe Policy::Follower do
|
5
|
+
|
6
|
+
before do
|
7
|
+
|
8
|
+
Transaction = Class.new Struct.new(:sum)
|
9
|
+
|
10
|
+
module Policies
|
11
|
+
|
12
|
+
class Consistency < Policy.new(:debet, :credit)
|
13
|
+
|
14
|
+
validates :debet, :credit, presence: true
|
15
|
+
validates :sum, numericality: { equal_to: 0 }, allow_nil: true
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def sum
|
20
|
+
debet && credit && (credit.sum + debet.sum)
|
21
|
+
end
|
22
|
+
|
23
|
+
end # class Consistency
|
24
|
+
|
25
|
+
end # module Policy
|
26
|
+
|
27
|
+
# The follower class to be tested
|
28
|
+
class Transfer < Struct.new(:withdrawal, :enrollment)
|
29
|
+
include Policy::Follower
|
30
|
+
|
31
|
+
use_policies Policies do
|
32
|
+
follow_policy :Consistency, :withdrawal, :enrollment, as: :consistency
|
33
|
+
end
|
34
|
+
|
35
|
+
end # class Transfer
|
36
|
+
|
37
|
+
end # before
|
38
|
+
|
39
|
+
let(:withdrawal) { Transaction.new(-100) }
|
40
|
+
subject { Transfer.new withdrawal, enrollment }
|
41
|
+
|
42
|
+
describe "#follow_policies!" do
|
43
|
+
|
44
|
+
context "when policy is met" do
|
45
|
+
|
46
|
+
let(:enrollment) { Transaction.new(100) }
|
47
|
+
|
48
|
+
it "passes if the policy is met" do
|
49
|
+
expect { subject.follow_policies! }.not_to raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
end # context
|
53
|
+
|
54
|
+
context "when policy is broken" do
|
55
|
+
|
56
|
+
let(:enrollment) { Transaction.new(200) }
|
57
|
+
|
58
|
+
it "fails if the policy is broken" do
|
59
|
+
expect { subject.follow_policies! }.to raise_error
|
60
|
+
end
|
61
|
+
|
62
|
+
end # context
|
63
|
+
|
64
|
+
end # describe #follow_policies!
|
65
|
+
|
66
|
+
describe "#follow_policies?" do
|
67
|
+
|
68
|
+
context "when policy is met" do
|
69
|
+
|
70
|
+
let(:enrollment) { Transaction.new(100) }
|
71
|
+
|
72
|
+
it "returns true if the policy is met" do
|
73
|
+
expect(subject).to be_follow_policies
|
74
|
+
end
|
75
|
+
|
76
|
+
end # context
|
77
|
+
|
78
|
+
context "when policy is broken" do
|
79
|
+
|
80
|
+
let(:enrollment) { Transaction.new(200) }
|
81
|
+
|
82
|
+
it "returns false if the policy is broken" do
|
83
|
+
expect(subject).not_to be_follow_policies
|
84
|
+
end
|
85
|
+
|
86
|
+
end # context
|
87
|
+
|
88
|
+
end # describe #follow_policies!
|
89
|
+
|
90
|
+
after do
|
91
|
+
%i(Transaction Transfer Policies)
|
92
|
+
.each { |const| Object.__send__(:remove_const, const) }
|
93
|
+
end
|
94
|
+
|
95
|
+
end # describe Policy::Follower
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "ostruct"
|
3
|
+
|
4
|
+
describe Policy::Follower::FollowedPolicies do
|
5
|
+
|
6
|
+
it "is a hash" do
|
7
|
+
expect(subject).to be_kind_of Hash
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#add" do
|
11
|
+
|
12
|
+
let(:policy) { double :policy, name: :foo }
|
13
|
+
|
14
|
+
it "registers a policy" do
|
15
|
+
expect { subject.add policy }.to change { subject }.to(foo: policy)
|
16
|
+
end
|
17
|
+
|
18
|
+
end # describe #add
|
19
|
+
|
20
|
+
describe "#apply_to" do
|
21
|
+
|
22
|
+
let(:follower) { double }
|
23
|
+
|
24
|
+
before do
|
25
|
+
%i(first second third).each do |item|
|
26
|
+
subject.add double(name: item, apply_to: nil)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
shared_examples "applying policies" do |applied_policies = nil|
|
31
|
+
|
32
|
+
before { applied_policies ||= subject.keys }
|
33
|
+
let(:skipped_policies) { subject.keys - applied_policies }
|
34
|
+
|
35
|
+
it "[applies policies]" do
|
36
|
+
policies = applied_policies.map(&subject.method(:[]))
|
37
|
+
|
38
|
+
policies.each do |policy|
|
39
|
+
expect(policy).to receive(:apply_to).with(follower).ordered
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "[skips policies]" do
|
44
|
+
policies = skipped_policies.map(&subject.method(:[]))
|
45
|
+
|
46
|
+
policies.each do |policy|
|
47
|
+
expect(policy).not_to receive(:apply_to)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end # shared examples
|
52
|
+
|
53
|
+
context "by default" do
|
54
|
+
|
55
|
+
after { subject.apply_to follower }
|
56
|
+
|
57
|
+
it_behaves_like "applying policies"
|
58
|
+
|
59
|
+
end # context
|
60
|
+
|
61
|
+
context "with a list of names" do
|
62
|
+
|
63
|
+
after { subject.apply_to follower, :third, :first }
|
64
|
+
|
65
|
+
it_behaves_like "applying policies", %i(third first)
|
66
|
+
|
67
|
+
end # context
|
68
|
+
|
69
|
+
context "with a repetitive names" do
|
70
|
+
|
71
|
+
after { subject.apply_to follower, :third, :third, :third }
|
72
|
+
|
73
|
+
it_behaves_like "applying policies", %i(third third third)
|
74
|
+
|
75
|
+
end # context
|
76
|
+
|
77
|
+
context "with an array of names" do
|
78
|
+
|
79
|
+
after { subject.apply_to follower, %w(third first forth) }
|
80
|
+
|
81
|
+
it_behaves_like "applying policies", %i(third first)
|
82
|
+
|
83
|
+
end # context
|
84
|
+
|
85
|
+
end # describe #apply_to
|
86
|
+
|
87
|
+
end # describe Policy::Follower::FollowedPolicies
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "ostruct"
|
3
|
+
|
4
|
+
describe Policy::Follower::FollowedPolicy do
|
5
|
+
|
6
|
+
before { module Namespace; class Policy < ::Policy.new(:foo, :bar); end; end }
|
7
|
+
after { Object.send :remove_const, :Namespace }
|
8
|
+
|
9
|
+
let(:namespace) { Namespace }
|
10
|
+
let(:policy_class) { Namespace::Policy }
|
11
|
+
|
12
|
+
describe ".new" do
|
13
|
+
|
14
|
+
shared_examples "refusing wrong number of attributes" do |*list|
|
15
|
+
|
16
|
+
subject { described_class.new nil, policy_class, :policy, *list }
|
17
|
+
|
18
|
+
it "raises ArgumentError" do
|
19
|
+
expect { subject }.to raise_error(ArgumentError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets a proper message for the exception" do
|
23
|
+
begin
|
24
|
+
subject
|
25
|
+
rescue => err
|
26
|
+
expect(err.message).to eq(
|
27
|
+
"#{ policy_class } requires 2 attribute(s)." \
|
28
|
+
" #{ list } cannot be assigned."
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end # shared examples
|
34
|
+
|
35
|
+
it_behaves_like "refusing wrong number of attributes", :foo
|
36
|
+
it_behaves_like "refusing wrong number of attributes", :foo, :bar, :baz
|
37
|
+
|
38
|
+
end # describe .new
|
39
|
+
|
40
|
+
describe "#name" do
|
41
|
+
|
42
|
+
context "when name is set to nil" do
|
43
|
+
|
44
|
+
subject { described_class.new nil, policy_class, nil, :foo, :bar }
|
45
|
+
|
46
|
+
it "assigns uuid" do
|
47
|
+
expect(subject.name.to_s).to match(/^\h{8}-(\h{4}-){3}\h{12}$/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "is a symbol" do
|
51
|
+
expect(subject.name).to be_kind_of Symbol
|
52
|
+
end
|
53
|
+
|
54
|
+
end # context
|
55
|
+
|
56
|
+
context "when name is set explicitly" do
|
57
|
+
|
58
|
+
subject { described_class.new nil, policy_class, "policy", :foo, :bar }
|
59
|
+
|
60
|
+
it "returns the symbolized name" do
|
61
|
+
expect(subject.name).to eq :policy
|
62
|
+
end
|
63
|
+
|
64
|
+
end # context
|
65
|
+
|
66
|
+
end # describe #name
|
67
|
+
|
68
|
+
describe "#policy" do
|
69
|
+
|
70
|
+
let(:policy_name) { :Policy }
|
71
|
+
|
72
|
+
shared_examples "policy object class" do
|
73
|
+
|
74
|
+
it "returns the constant" do
|
75
|
+
expect(subject.policy).to eq policy_class
|
76
|
+
end
|
77
|
+
|
78
|
+
end # context
|
79
|
+
|
80
|
+
it_behaves_like "policy object class" do
|
81
|
+
subject { described_class.new :foo, policy_class, :foo, :bar, :baz }
|
82
|
+
end
|
83
|
+
|
84
|
+
it_behaves_like "policy object class" do
|
85
|
+
subject { described_class.new namespace, policy_name, :foo, :bar, :baz }
|
86
|
+
end
|
87
|
+
|
88
|
+
end # describe #policy
|
89
|
+
|
90
|
+
describe "#attributes" do
|
91
|
+
|
92
|
+
let(:attributes) { %i(foo bar) }
|
93
|
+
subject { described_class.new nil, policy_class, :foo, *attributes }
|
94
|
+
|
95
|
+
it "is set by the initializer" do
|
96
|
+
expect(subject.attributes).to eq attributes
|
97
|
+
end
|
98
|
+
|
99
|
+
end # describe #attributes
|
100
|
+
|
101
|
+
describe "#apply_to" do
|
102
|
+
|
103
|
+
let(:attributes) { { foo: :bar, bar: :baz } }
|
104
|
+
let(:follower) { OpenStruct.new(attributes) }
|
105
|
+
|
106
|
+
subject do
|
107
|
+
described_class.new nil, policy_class, nil, *attributes.keys
|
108
|
+
end
|
109
|
+
|
110
|
+
it "calls policy_class validation with follower attributes" do
|
111
|
+
expect(policy_class).to receive(:apply).with(*attributes.values)
|
112
|
+
subject.apply_to(follower)
|
113
|
+
end
|
114
|
+
|
115
|
+
end # describe #apply_to
|
116
|
+
|
117
|
+
end # describe Policy::Follower::Policy
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Follower::Names do
|
4
|
+
|
5
|
+
describe ".from" do
|
6
|
+
|
7
|
+
shared_examples "normalizing from" do |*source|
|
8
|
+
|
9
|
+
subject { described_class.from(*source) }
|
10
|
+
it { is_expected.to eq %i(foo bar baz foo) }
|
11
|
+
|
12
|
+
end # shared examples
|
13
|
+
|
14
|
+
it_behaves_like "normalizing from", %w(foo bar baz foo)
|
15
|
+
it_behaves_like "normalizing from", *%w(foo bar baz foo)
|
16
|
+
|
17
|
+
end # describe .from
|
18
|
+
|
19
|
+
end # describe Policy::Follower::Names
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Follower do
|
4
|
+
|
5
|
+
before { Test = Class.new.__send__(:include, described_class) }
|
6
|
+
after { Object.send :remove_const, :Test }
|
7
|
+
|
8
|
+
let(:test_class) { Test }
|
9
|
+
subject { test_class.new }
|
10
|
+
|
11
|
+
it "includes Policy::Validations" do
|
12
|
+
expect(test_class).to include Policy::Validations
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ".followed_policies" do
|
16
|
+
|
17
|
+
let(:followed_policies) { Policy::Follower::FollowedPolicies }
|
18
|
+
|
19
|
+
it "returns the AppiedPolicies object" do
|
20
|
+
expect(test_class.followed_policies).to be_kind_of followed_policies
|
21
|
+
end
|
22
|
+
|
23
|
+
end # describe .followed_policies
|
24
|
+
|
25
|
+
describe ".follow_policy" do
|
26
|
+
|
27
|
+
let(:followed_policy) { Policy::Follower::FollowedPolicy }
|
28
|
+
|
29
|
+
let(:policy) { double name: :foo }
|
30
|
+
let(:policy_class) { double }
|
31
|
+
let(:name) { double }
|
32
|
+
let(:attributes) { [double, double] }
|
33
|
+
|
34
|
+
before { allow(followed_policy).to receive(:new) { policy } }
|
35
|
+
|
36
|
+
context "by default" do
|
37
|
+
|
38
|
+
after { test_class.follow_policy policy_class, *attributes }
|
39
|
+
|
40
|
+
it "creates new followed policy" do
|
41
|
+
expect(followed_policy)
|
42
|
+
.to receive(:new)
|
43
|
+
.with(test_class, policy_class, nil, *attributes)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "adds new policy to .followed_policies" do
|
47
|
+
expect(test_class.followed_policies).to receive(:add).with(policy)
|
48
|
+
end
|
49
|
+
|
50
|
+
end # context
|
51
|
+
|
52
|
+
context "as: name" do
|
53
|
+
|
54
|
+
after { test_class.follow_policy(policy_class, *attributes, as: name) }
|
55
|
+
|
56
|
+
it "creates named followed policy" do
|
57
|
+
expect(followed_policy)
|
58
|
+
.to receive(:new)
|
59
|
+
.with(test_class, policy_class, name, *attributes)
|
60
|
+
end
|
61
|
+
|
62
|
+
end # context
|
63
|
+
|
64
|
+
context "inside #use_policies" do
|
65
|
+
|
66
|
+
let(:namespace) { double }
|
67
|
+
|
68
|
+
subject do
|
69
|
+
test_class.use_policies namespace do
|
70
|
+
follow_policy :foo, as: :bar
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "sends the namespace to followed policy" do
|
75
|
+
expect(followed_policy)
|
76
|
+
.to receive(:new).with(namespace, :foo, :bar)
|
77
|
+
subject
|
78
|
+
end
|
79
|
+
|
80
|
+
it "doesn't change default namespace" do
|
81
|
+
subject
|
82
|
+
expect(followed_policy)
|
83
|
+
.to receive(:new).with(test_class, :foo, :bar)
|
84
|
+
test_class.follow_policy :foo, as: :bar
|
85
|
+
end
|
86
|
+
|
87
|
+
end # context
|
88
|
+
|
89
|
+
end # describe .follow_policy
|
90
|
+
|
91
|
+
describe "#follow_policies!" do
|
92
|
+
|
93
|
+
context "without names" do
|
94
|
+
|
95
|
+
after { subject.follow_policies! }
|
96
|
+
|
97
|
+
it "applies .followed_policies to itself" do
|
98
|
+
expect(test_class.followed_policies)
|
99
|
+
.to receive(:apply_to).with(subject)
|
100
|
+
end
|
101
|
+
|
102
|
+
end # context
|
103
|
+
|
104
|
+
context "with names" do
|
105
|
+
|
106
|
+
let(:names) { %i(foo bar baz) }
|
107
|
+
after { subject.follow_policies!(*names) }
|
108
|
+
|
109
|
+
it "applies .followed_policies to itself with names" do
|
110
|
+
expect(test_class.followed_policies)
|
111
|
+
.to receive(:apply_to).with(subject, *names)
|
112
|
+
end
|
113
|
+
|
114
|
+
end # context
|
115
|
+
|
116
|
+
context "when a ViolationError is raised" do
|
117
|
+
|
118
|
+
let(:error) { Policy::ViolationError.allocate }
|
119
|
+
let(:messages) { %w(foo bar baz) }
|
120
|
+
|
121
|
+
before do
|
122
|
+
allow(error).to receive(:messages) { messages }
|
123
|
+
allow(test_class.followed_policies).to receive(:apply_to) { fail error }
|
124
|
+
end
|
125
|
+
|
126
|
+
it "populates messages with errors" do
|
127
|
+
expect { subject.follow_policies! rescue nil }
|
128
|
+
.to change { subject.__send__(:errors).messages }
|
129
|
+
.to(base: messages)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "re-raises the exception" do
|
133
|
+
expect { subject.follow_policies! }.to raise_error(error)
|
134
|
+
end
|
135
|
+
|
136
|
+
end # context
|
137
|
+
|
138
|
+
end # describe #follow_policies!
|
139
|
+
|
140
|
+
describe "#follow_policies?" do
|
141
|
+
|
142
|
+
before { allow(subject).to receive(:follow_policies!) }
|
143
|
+
|
144
|
+
it "calls #follow_policies! without names" do
|
145
|
+
expect(subject).to receive(:follow_policies!)
|
146
|
+
subject.follow_policies?
|
147
|
+
end
|
148
|
+
|
149
|
+
it "calls #follow_policies! with names" do
|
150
|
+
names = %i(foo bar baz)
|
151
|
+
|
152
|
+
expect(subject).to receive(:follow_policies!).with(*names)
|
153
|
+
subject.follow_policies?(*names)
|
154
|
+
end
|
155
|
+
|
156
|
+
context "wheh #follow_policies! doesn't raise an error" do
|
157
|
+
|
158
|
+
before { allow(subject).to receive(:follow_policies!) { nil } }
|
159
|
+
|
160
|
+
it "returns true" do
|
161
|
+
expect(subject.follow_policies?).to eq true
|
162
|
+
end
|
163
|
+
|
164
|
+
end # context
|
165
|
+
|
166
|
+
context "wheh #folow_policies! raises ViolationError" do
|
167
|
+
|
168
|
+
let(:error) { Policy::ViolationError.allocate }
|
169
|
+
before { allow(subject).to receive(:follow_policies!) { fail error } }
|
170
|
+
|
171
|
+
it "returns false" do
|
172
|
+
expect(subject.follow_policies?).to eq false
|
173
|
+
end
|
174
|
+
|
175
|
+
end # context
|
176
|
+
|
177
|
+
context "wheh #follow_policies! raises RuntimeError" do
|
178
|
+
|
179
|
+
let(:error) { StandardError.allocate }
|
180
|
+
before { allow(subject).to receive(:follow_policies!) { fail error } }
|
181
|
+
|
182
|
+
it "fails" do
|
183
|
+
expect { subject.follow_policies? }.to raise_error(error)
|
184
|
+
end
|
185
|
+
|
186
|
+
end # context
|
187
|
+
|
188
|
+
end # describe #follow_policies?
|
189
|
+
|
190
|
+
describe "#follow_policy!" do
|
191
|
+
|
192
|
+
before { allow(subject).to receive(:follow_policies!) }
|
193
|
+
|
194
|
+
it "is an alias for #follow_policies!" do
|
195
|
+
expect(subject).to receive(:follow_policies!).with :foo
|
196
|
+
subject.follow_policy! :foo
|
197
|
+
end
|
198
|
+
|
199
|
+
it "requires an argument" do
|
200
|
+
expect(subject.method(:follow_policy!).arity).to eq 1
|
201
|
+
end
|
202
|
+
|
203
|
+
end # describe #follow_policy!
|
204
|
+
|
205
|
+
describe "#follow_policy?" do
|
206
|
+
|
207
|
+
before { allow(subject).to receive(:follow_policies?) }
|
208
|
+
|
209
|
+
it "is an alias for #follow_policies?" do
|
210
|
+
expect(subject).to receive(:follow_policies?).with :foo
|
211
|
+
subject.follow_policy? :foo
|
212
|
+
end
|
213
|
+
|
214
|
+
it "requires an argument" do
|
215
|
+
expect(subject.method(:follow_policy?).arity).to eq 1
|
216
|
+
end
|
217
|
+
|
218
|
+
end # describe #follow_policy?
|
219
|
+
|
220
|
+
end # describe Policy::Follower
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Interface do
|
4
|
+
|
5
|
+
before { Test = Class.new.send :include, described_class }
|
6
|
+
after { Object.send :remove_const, :Test }
|
7
|
+
|
8
|
+
let(:test_class) { Test }
|
9
|
+
subject { test_class.new }
|
10
|
+
|
11
|
+
it "includes Policy::Validations" do
|
12
|
+
expect(test_class).to include Policy::Validations
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#apply" do
|
16
|
+
|
17
|
+
context "when #valid? returns true" do
|
18
|
+
|
19
|
+
before { allow(subject).to receive(:valid?).and_return true }
|
20
|
+
|
21
|
+
it "doesn't raise error" do
|
22
|
+
expect { subject.apply }.not_to raise_error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when #valid? returns false" do
|
27
|
+
|
28
|
+
before { allow(subject).to receive(:valid?).and_return false }
|
29
|
+
|
30
|
+
it "raises ViolationError" do
|
31
|
+
expect { subject.apply }.to raise_error(Policy::ViolationError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "adds the policy to Exception" do
|
35
|
+
expect(Policy::ViolationError).to receive(:new).with(subject).once
|
36
|
+
subject.apply rescue nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end # describe #apply
|
41
|
+
|
42
|
+
describe "#messages" do
|
43
|
+
|
44
|
+
context "when #errors are present" do
|
45
|
+
|
46
|
+
let(:messages) { %w(foo bar) }
|
47
|
+
let(:errors) { double :errors, messages: { foo: messages } }
|
48
|
+
|
49
|
+
it "extracts a plain array of error messages" do
|
50
|
+
allow(subject).to receive(:errors) { errors }
|
51
|
+
expect(subject.messages).to eq messages
|
52
|
+
end
|
53
|
+
|
54
|
+
end # context
|
55
|
+
|
56
|
+
context "when #errors are absent" do
|
57
|
+
|
58
|
+
it "returns an empty array" do
|
59
|
+
expect(subject.messages).to eq []
|
60
|
+
end
|
61
|
+
|
62
|
+
end # context
|
63
|
+
|
64
|
+
end # describe #messages
|
65
|
+
|
66
|
+
describe ".apply" do
|
67
|
+
|
68
|
+
let(:attributes) { %i(foo bar) }
|
69
|
+
let(:follower) { double apply: nil }
|
70
|
+
|
71
|
+
it "creates a policy object with the attributes" do
|
72
|
+
expect(test_class).to receive(:new).with(attributes) { follower }
|
73
|
+
test_class.apply attributes
|
74
|
+
end
|
75
|
+
|
76
|
+
it "validates the policy object" do
|
77
|
+
expect(test_class).to receive_message_chain :new, :apply
|
78
|
+
test_class.apply attributes
|
79
|
+
end
|
80
|
+
|
81
|
+
end # describe .apply
|
82
|
+
|
83
|
+
end # describe Policy::Inteface
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Validations do
|
4
|
+
|
5
|
+
let(:validations) { ActiveModel::Validations }
|
6
|
+
let(:methods) { validations.public_instance_methods }
|
7
|
+
let(:test_class) { Class.new.send :include, described_class }
|
8
|
+
|
9
|
+
it "includes ActiveModel::Validatons" do
|
10
|
+
expect(test_class).to include validations
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|