attestor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +9 -0
- data/.metrics +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +10 -0
- data/.yardopts +3 -0
- data/Gemfile +5 -0
- data/Guardfile +15 -0
- data/LICENSE +21 -0
- data/README.md +308 -0
- data/Rakefile +22 -0
- data/attestor.gemspec +24 -0
- data/config/metrics/STYLEGUIDE +230 -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 +15 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +75 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +6 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/attestor/invalid_error.rb +44 -0
- data/lib/attestor/policy/and.rb +36 -0
- data/lib/attestor/policy/factory.rb +88 -0
- data/lib/attestor/policy/negator.rb +53 -0
- data/lib/attestor/policy/node.rb +58 -0
- data/lib/attestor/policy/not.rb +48 -0
- data/lib/attestor/policy/or.rb +36 -0
- data/lib/attestor/policy/xor.rb +36 -0
- data/lib/attestor/policy.rb +121 -0
- data/lib/attestor/validations/collection.rb +73 -0
- data/lib/attestor/validations/item.rb +87 -0
- data/lib/attestor/validations/message.rb +55 -0
- data/lib/attestor/validations.rb +81 -0
- data/lib/attestor/version.rb +9 -0
- data/lib/attestor.rb +26 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/policies.rb +49 -0
- data/spec/tests/invalid_error_spec.rb +57 -0
- data/spec/tests/policy/and_spec.rb +40 -0
- data/spec/tests/policy/factory_spec.rb +100 -0
- data/spec/tests/policy/negator_spec.rb +57 -0
- data/spec/tests/policy/node_spec.rb +44 -0
- data/spec/tests/policy/not_spec.rb +40 -0
- data/spec/tests/policy/or_spec.rb +40 -0
- data/spec/tests/policy/xor_spec.rb +48 -0
- data/spec/tests/policy_spec.rb +111 -0
- data/spec/tests/validations/collection_spec.rb +100 -0
- data/spec/tests/validations/item_spec.rb +153 -0
- data/spec/tests/validations/message_spec.rb +71 -0
- data/spec/tests/validations_spec.rb +126 -0
- metadata +143 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# describe #valid_policy and #invalid_policy builders
|
4
|
+
# also describes shared examples for all policies
|
5
|
+
require "support/policies"
|
6
|
+
|
7
|
+
describe Attestor::Policy::Not do
|
8
|
+
|
9
|
+
subject { described_class.new item }
|
10
|
+
|
11
|
+
describe ".new" do
|
12
|
+
|
13
|
+
let(:item) { valid_policy }
|
14
|
+
|
15
|
+
it_behaves_like "creating a node"
|
16
|
+
it_behaves_like "creating an immutable object"
|
17
|
+
|
18
|
+
end # context
|
19
|
+
|
20
|
+
describe "#validate" do
|
21
|
+
|
22
|
+
context "when a part is invalid" do
|
23
|
+
|
24
|
+
let(:item) { invalid_policy }
|
25
|
+
|
26
|
+
it_behaves_like "passing validation"
|
27
|
+
|
28
|
+
end # context
|
29
|
+
|
30
|
+
context "when a part is valid" do
|
31
|
+
|
32
|
+
let(:item) { valid_policy }
|
33
|
+
|
34
|
+
it_behaves_like "failing validation"
|
35
|
+
|
36
|
+
end # context
|
37
|
+
|
38
|
+
end # describe #validate
|
39
|
+
|
40
|
+
end # describe Policy::Base::Not
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# describe #valid_policy and #invalid_policy builders
|
4
|
+
# also describes shared examples for all policies
|
5
|
+
require "support/policies"
|
6
|
+
|
7
|
+
describe Attestor::Policy::Or do
|
8
|
+
|
9
|
+
subject { described_class.new items }
|
10
|
+
|
11
|
+
describe ".new" do
|
12
|
+
|
13
|
+
let(:items) { [valid_policy] }
|
14
|
+
|
15
|
+
it_behaves_like "creating a node"
|
16
|
+
it_behaves_like "creating an immutable object"
|
17
|
+
|
18
|
+
end # context
|
19
|
+
|
20
|
+
describe "#validate" do
|
21
|
+
|
22
|
+
context "when valid part exists" do
|
23
|
+
|
24
|
+
let(:items) { [valid_policy, valid_policy, invalid_policy] }
|
25
|
+
|
26
|
+
it_behaves_like "passing validation"
|
27
|
+
|
28
|
+
end # context
|
29
|
+
|
30
|
+
context "when all parts are invalid" do
|
31
|
+
|
32
|
+
let(:items) { 3.times.map { invalid_policy } }
|
33
|
+
|
34
|
+
it_behaves_like "failing validation"
|
35
|
+
|
36
|
+
end # context
|
37
|
+
|
38
|
+
end # describe #validate
|
39
|
+
|
40
|
+
end # describe Policy::Base::Not
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# describe #valid_policy and #invalid_policy builders
|
4
|
+
# also describes shared examples for all policies
|
5
|
+
require "support/policies"
|
6
|
+
|
7
|
+
describe Attestor::Policy::Xor do
|
8
|
+
|
9
|
+
subject { described_class.new items }
|
10
|
+
|
11
|
+
describe ".new" do
|
12
|
+
|
13
|
+
let(:items) { [valid_policy] }
|
14
|
+
|
15
|
+
it_behaves_like "creating a node"
|
16
|
+
it_behaves_like "creating an immutable object"
|
17
|
+
|
18
|
+
end # context
|
19
|
+
|
20
|
+
describe "#validate" do
|
21
|
+
|
22
|
+
context "when both valid and invalid parts exist" do
|
23
|
+
|
24
|
+
let(:items) { [valid_policy, valid_policy, invalid_policy] }
|
25
|
+
|
26
|
+
it_behaves_like "passing validation"
|
27
|
+
|
28
|
+
end # context
|
29
|
+
|
30
|
+
context "when all parts are valid" do
|
31
|
+
|
32
|
+
let(:items) { 3.times.map { valid_policy } }
|
33
|
+
|
34
|
+
it_behaves_like "failing validation"
|
35
|
+
|
36
|
+
end # context
|
37
|
+
|
38
|
+
context "when all parts are invalid" do
|
39
|
+
|
40
|
+
let(:items) { 3.times.map { invalid_policy } }
|
41
|
+
|
42
|
+
it_behaves_like "failing validation"
|
43
|
+
|
44
|
+
end # context
|
45
|
+
|
46
|
+
end # describe #validate
|
47
|
+
|
48
|
+
end # describe Policy::Base::Not
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Attestor::Policy do
|
4
|
+
|
5
|
+
let(:factory) { Attestor::Policy::Factory }
|
6
|
+
let(:validator) { Attestor::Validations }
|
7
|
+
let(:invalid) { Attestor::InvalidError.new subject, [] }
|
8
|
+
let(:others) { 2.times { double } }
|
9
|
+
|
10
|
+
let(:test_class) { Class.new.send(:include, described_class) }
|
11
|
+
before { Test = test_class }
|
12
|
+
after { Object.send :remove_const, :Test }
|
13
|
+
subject { test_class.new }
|
14
|
+
|
15
|
+
it "is a factory" do
|
16
|
+
expect(test_class).to be_kind_of factory
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".new" do
|
20
|
+
|
21
|
+
it "creates a validator" do
|
22
|
+
expect(subject).to be_kind_of validator
|
23
|
+
end
|
24
|
+
|
25
|
+
end # describe .new
|
26
|
+
|
27
|
+
describe "#valid?" do
|
28
|
+
|
29
|
+
context "when #validate method fails" do
|
30
|
+
|
31
|
+
before { allow(subject).to receive(:validate) { fail invalid } }
|
32
|
+
|
33
|
+
it "returns false" do
|
34
|
+
expect(subject.valid?).to eq false
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when #validate method passes" do
|
40
|
+
|
41
|
+
before { allow(subject).to receive(:validate) { nil } }
|
42
|
+
|
43
|
+
it "returns true" do
|
44
|
+
expect(subject.valid?).to eq true
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end # describe #valid?
|
50
|
+
|
51
|
+
describe "#invalid?" do
|
52
|
+
|
53
|
+
context "when #validate method fails" do
|
54
|
+
|
55
|
+
before { allow(subject).to receive(:validate) { fail invalid } }
|
56
|
+
|
57
|
+
it "returns true" do
|
58
|
+
expect(subject.invalid?).to eq true
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when #validate method passes" do
|
64
|
+
|
65
|
+
before { allow(subject).to receive(:validate) { nil } }
|
66
|
+
|
67
|
+
it "returns false" do
|
68
|
+
expect(subject.invalid?).to eq false
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end # describe #invalid?
|
74
|
+
|
75
|
+
describe "#and" do
|
76
|
+
|
77
|
+
it "calls .and class factory method with self" do
|
78
|
+
expect(test_class).to receive(:and).with(subject, *others)
|
79
|
+
subject.and(*others)
|
80
|
+
end
|
81
|
+
|
82
|
+
end # describe #and
|
83
|
+
|
84
|
+
describe "#or" do
|
85
|
+
|
86
|
+
it "calls .or class factory method with self" do
|
87
|
+
expect(test_class).to receive(:or).with(subject, *others)
|
88
|
+
subject.or(*others)
|
89
|
+
end
|
90
|
+
|
91
|
+
end # describe #or
|
92
|
+
|
93
|
+
describe "#xor" do
|
94
|
+
|
95
|
+
it "calls .xor class factory method with self" do
|
96
|
+
expect(test_class).to receive(:xor).with(subject, *others)
|
97
|
+
subject.xor(*others)
|
98
|
+
end
|
99
|
+
|
100
|
+
end # describe #xor
|
101
|
+
|
102
|
+
describe "#not" do
|
103
|
+
|
104
|
+
it "calls .not class factory method with self" do
|
105
|
+
expect(test_class).to receive(:not).with(subject)
|
106
|
+
subject.not
|
107
|
+
end
|
108
|
+
|
109
|
+
end # describe #not
|
110
|
+
|
111
|
+
end # describe Attestor::Policy
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Attestor::Validations::Collection do
|
4
|
+
|
5
|
+
let(:item_class) { Attestor::Validations::Item }
|
6
|
+
|
7
|
+
describe ".new" do
|
8
|
+
|
9
|
+
it "creates a collection" do
|
10
|
+
expect(subject).to be_kind_of Enumerable
|
11
|
+
end
|
12
|
+
|
13
|
+
it "creates an immutable object" do
|
14
|
+
expect(subject).to be_frozen
|
15
|
+
end
|
16
|
+
|
17
|
+
end # .new
|
18
|
+
|
19
|
+
describe "#each" do
|
20
|
+
|
21
|
+
it "returns an enumerator" do
|
22
|
+
expect(subject.each).to be_kind_of Enumerator
|
23
|
+
end
|
24
|
+
|
25
|
+
it "iterates trough the unique item names" do
|
26
|
+
items = %w(foo bar foo).map(&item_class.method(:new))
|
27
|
+
subject = described_class.new items
|
28
|
+
|
29
|
+
expect(subject.to_a).to match_array %i(foo bar)
|
30
|
+
end
|
31
|
+
|
32
|
+
end # describe #each
|
33
|
+
|
34
|
+
describe "#add" do
|
35
|
+
|
36
|
+
context "without options" do
|
37
|
+
|
38
|
+
let(:result) { subject.add("foo") }
|
39
|
+
|
40
|
+
it "returns the collection" do
|
41
|
+
expect(result).to be_kind_of described_class
|
42
|
+
end
|
43
|
+
|
44
|
+
it "adds item to the collection" do
|
45
|
+
item = result.first
|
46
|
+
expect(item).to eq :foo
|
47
|
+
end
|
48
|
+
|
49
|
+
it "preserves existing items" do
|
50
|
+
expect(result.add(:bar).to_a).to contain_exactly :foo, :bar
|
51
|
+
end
|
52
|
+
|
53
|
+
end # context
|
54
|
+
|
55
|
+
context "with options" do
|
56
|
+
|
57
|
+
let(:result) { subject.add "foo", only: [:foo] }
|
58
|
+
|
59
|
+
it "adds item to the collection" do
|
60
|
+
expect(result.to_a).to eq [:foo]
|
61
|
+
expect(result.set(:foo).to_a).to eq [:foo]
|
62
|
+
expect(result.set(:all).to_a).to eq []
|
63
|
+
end
|
64
|
+
|
65
|
+
end # context
|
66
|
+
|
67
|
+
context "existing item" do
|
68
|
+
|
69
|
+
subject { described_class.new.add "foo" }
|
70
|
+
|
71
|
+
it "returns itself" do
|
72
|
+
expect(subject.add "foo").to eq subject
|
73
|
+
end
|
74
|
+
|
75
|
+
end # context
|
76
|
+
|
77
|
+
end # describe #add
|
78
|
+
|
79
|
+
describe "#context" do
|
80
|
+
|
81
|
+
subject do
|
82
|
+
described_class.new
|
83
|
+
.add("foo", only: %w(cad cam))
|
84
|
+
.add("bar", except: %w(cad))
|
85
|
+
.add("baz", except: %w(cam))
|
86
|
+
end
|
87
|
+
|
88
|
+
it "returns a collection" do
|
89
|
+
expect(subject.set "all").to be_kind_of described_class
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns a set of items used in given context" do
|
93
|
+
expect(subject.set("cad").to_a).to contain_exactly :foo, :baz
|
94
|
+
expect(subject.set("cam").to_a).to contain_exactly :foo, :bar
|
95
|
+
expect(subject.set("all").to_a).to contain_exactly :bar, :baz
|
96
|
+
end
|
97
|
+
|
98
|
+
end # describe #context
|
99
|
+
|
100
|
+
end # describe Attestor::Collection
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Attestor::Validations::Item do
|
4
|
+
|
5
|
+
subject { described_class.new "foo" }
|
6
|
+
|
7
|
+
describe ".new" do
|
8
|
+
|
9
|
+
it "is immutable" do
|
10
|
+
expect(subject).to be_frozen
|
11
|
+
end
|
12
|
+
|
13
|
+
it "accepts item option :except" do
|
14
|
+
expect { described_class.new "foo", except: :bar }.not_to raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it "accepts array option :except" do
|
18
|
+
expect { described_class.new "foo", except: %w(bar) }.not_to raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "ignores repetitive :except items" do
|
22
|
+
expect(described_class.new "foo", except: %i(bar bar))
|
23
|
+
.to eq(described_class.new "foo", except: %i(bar))
|
24
|
+
end
|
25
|
+
|
26
|
+
it "accepts item option :only" do
|
27
|
+
expect { described_class.new "foo", only: :bar }.not_to raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it "accepts array option :only" do
|
31
|
+
expect { described_class.new "foo", only: %w(bar) }.not_to raise_error
|
32
|
+
end
|
33
|
+
|
34
|
+
it "ignores repetitive :only items" do
|
35
|
+
expect(described_class.new "foo", only: %i(bar bar))
|
36
|
+
.to eq(described_class.new "foo", only: %i(bar))
|
37
|
+
end
|
38
|
+
|
39
|
+
end # describe .new
|
40
|
+
|
41
|
+
describe ".name" do
|
42
|
+
|
43
|
+
it "is initialized as a symbol" do
|
44
|
+
expect(subject.name).to eq :foo
|
45
|
+
end
|
46
|
+
|
47
|
+
end # describe .name
|
48
|
+
|
49
|
+
describe "#==" do
|
50
|
+
|
51
|
+
subject { described_class.new :foo, except: [:foo], only: %i(bar) }
|
52
|
+
|
53
|
+
context "item with the same name and options" do
|
54
|
+
|
55
|
+
let(:other) { described_class.new :foo, except: %i(foo), only: %i(bar) }
|
56
|
+
|
57
|
+
it "returns true" do
|
58
|
+
expect(subject == other).to eq true
|
59
|
+
expect(subject).to eq other
|
60
|
+
end
|
61
|
+
|
62
|
+
end # context
|
63
|
+
|
64
|
+
context "item with another name" do
|
65
|
+
|
66
|
+
let(:other) { described_class.new :baz, except: %i(foo), only: %i(bar) }
|
67
|
+
|
68
|
+
it "returns false" do
|
69
|
+
expect(subject == other).to eq false
|
70
|
+
expect(subject).not_to eq other
|
71
|
+
end
|
72
|
+
|
73
|
+
end # context
|
74
|
+
|
75
|
+
context "item with another blacklist" do
|
76
|
+
|
77
|
+
let(:other) { described_class.new :foo, except: %i(baz), only: %i(bar) }
|
78
|
+
|
79
|
+
it "returns false" do
|
80
|
+
expect(subject == other).to eq false
|
81
|
+
expect(subject).not_to eq other
|
82
|
+
end
|
83
|
+
|
84
|
+
end # context
|
85
|
+
|
86
|
+
context "item with another whitelist" do
|
87
|
+
|
88
|
+
let(:other) { described_class.new :foo, except: %i(foo), only: %i(baz) }
|
89
|
+
|
90
|
+
it "returns false" do
|
91
|
+
expect(subject == other).to eq false
|
92
|
+
expect(subject).not_to eq other
|
93
|
+
end
|
94
|
+
|
95
|
+
end # context
|
96
|
+
|
97
|
+
context "not an item" do
|
98
|
+
|
99
|
+
let(:other) { "baz" }
|
100
|
+
|
101
|
+
it "returns false" do
|
102
|
+
expect(subject == other).to eq false
|
103
|
+
expect(subject).not_to eq other
|
104
|
+
end
|
105
|
+
|
106
|
+
end # context
|
107
|
+
|
108
|
+
end # describe #==
|
109
|
+
|
110
|
+
describe "#used_in_context?" do
|
111
|
+
|
112
|
+
context "not restricted" do
|
113
|
+
|
114
|
+
it { is_expected.to be_used_in_context :bar }
|
115
|
+
it { is_expected.to be_used_in_context "baz" }
|
116
|
+
|
117
|
+
end # context
|
118
|
+
|
119
|
+
context "blacklisted" do
|
120
|
+
|
121
|
+
subject { described_class.new "foo", except: %w(foo bar) }
|
122
|
+
|
123
|
+
it { is_expected.not_to be_used_in_context "foo" }
|
124
|
+
it { is_expected.not_to be_used_in_context :bar }
|
125
|
+
it { is_expected.to be_used_in_context "baz" }
|
126
|
+
|
127
|
+
end # context
|
128
|
+
|
129
|
+
context "whitelisted" do
|
130
|
+
|
131
|
+
subject { described_class.new "foo", only: %w(foo bar) }
|
132
|
+
|
133
|
+
it { is_expected.to be_used_in_context "foo" }
|
134
|
+
it { is_expected.to be_used_in_context :bar }
|
135
|
+
it { is_expected.not_to be_used_in_context "baz" }
|
136
|
+
|
137
|
+
end # context
|
138
|
+
|
139
|
+
context "white- and blacklisted" do
|
140
|
+
|
141
|
+
subject do
|
142
|
+
described_class.new "foo", only: %w(foo bar), except: %w(bar baz)
|
143
|
+
end
|
144
|
+
|
145
|
+
it { is_expected.to be_used_in_context "foo" }
|
146
|
+
it { is_expected.not_to be_used_in_context :bar }
|
147
|
+
it { is_expected.not_to be_used_in_context "baz" }
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end # describe #name
|
152
|
+
|
153
|
+
end # describe Attestor::Validation
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Attestor::Validations::Message do
|
4
|
+
|
5
|
+
let(:test_class) { Class.new }
|
6
|
+
before { TestModule = Module.new }
|
7
|
+
before { TestModule::TestObject = test_class }
|
8
|
+
after { Object.send :remove_const, :TestModule }
|
9
|
+
|
10
|
+
let(:scope) { test_class.new }
|
11
|
+
|
12
|
+
shared_examples "building frozen string" do
|
13
|
+
|
14
|
+
it { is_expected.to be_kind_of String }
|
15
|
+
it { is_expected.to be_frozen }
|
16
|
+
|
17
|
+
end # shared examples
|
18
|
+
|
19
|
+
describe ".new" do
|
20
|
+
|
21
|
+
context "with a symbol argument" do
|
22
|
+
|
23
|
+
subject { described_class.new :invalid, scope, foo: "bar" }
|
24
|
+
|
25
|
+
it_behaves_like "building frozen string"
|
26
|
+
|
27
|
+
it "translates the symbol in given scope" do
|
28
|
+
expect(I18n).to receive(:t) do |text, options|
|
29
|
+
expect(text).to eq :invalid
|
30
|
+
expect(options[:scope])
|
31
|
+
.to eq %w(attestor errors test_module/test_object)
|
32
|
+
expect(options[:default]).to eq "#{ scope } is invalid (invalid)"
|
33
|
+
expect(options[:foo]).to eq "bar"
|
34
|
+
""
|
35
|
+
end
|
36
|
+
subject
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns the translation" do
|
40
|
+
expect(subject).to eq "#{ scope } is invalid (invalid)"
|
41
|
+
end
|
42
|
+
|
43
|
+
end # context
|
44
|
+
|
45
|
+
context "with a non-symbolic argument" do
|
46
|
+
|
47
|
+
subject { described_class.new 1, scope }
|
48
|
+
|
49
|
+
it_behaves_like "building frozen string"
|
50
|
+
|
51
|
+
it "creates a stringified argument" do
|
52
|
+
expect(subject).to eq "1"
|
53
|
+
end
|
54
|
+
|
55
|
+
end # context
|
56
|
+
|
57
|
+
context "without options" do
|
58
|
+
|
59
|
+
subject { described_class.new :invalid, scope }
|
60
|
+
|
61
|
+
it_behaves_like "building frozen string"
|
62
|
+
|
63
|
+
it "returns the translation" do
|
64
|
+
expect(subject).to eq "#{ scope } is invalid (invalid)"
|
65
|
+
end
|
66
|
+
|
67
|
+
end # context
|
68
|
+
|
69
|
+
end # describe .new
|
70
|
+
|
71
|
+
end # Attestor::Validations::Invalid
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Attestor::Validations do
|
4
|
+
|
5
|
+
let(:collection_class) { Attestor::Validations::Collection }
|
6
|
+
let(:item_class) { Attestor::Validations::Item }
|
7
|
+
let(:message_class) { Attestor::Validations::Message }
|
8
|
+
let(:invalid_error) { Attestor::InvalidError }
|
9
|
+
let(:test_class) { Class.new.send(:include, described_class) }
|
10
|
+
|
11
|
+
before { Test = test_class }
|
12
|
+
after { Object.send :remove_const, :Test }
|
13
|
+
|
14
|
+
subject { test_class.new }
|
15
|
+
|
16
|
+
describe ".validations" do
|
17
|
+
|
18
|
+
it "returns a Collection" do
|
19
|
+
expect(test_class.validations).to be_kind_of collection_class
|
20
|
+
end
|
21
|
+
|
22
|
+
it "is empty by default" do
|
23
|
+
expect(test_class.validations.to_a).to be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
end # describe .validations
|
27
|
+
|
28
|
+
describe ".validate" do
|
29
|
+
|
30
|
+
context "without options" do
|
31
|
+
|
32
|
+
before { test_class.validate :foo }
|
33
|
+
|
34
|
+
it "adds the item to the collection" do
|
35
|
+
expect(test_class.validations.to_a).to eq [:foo]
|
36
|
+
end
|
37
|
+
|
38
|
+
end # context
|
39
|
+
|
40
|
+
context "with options" do
|
41
|
+
|
42
|
+
before { test_class.validate :foo, only: %w(bar baz), except: "bar" }
|
43
|
+
|
44
|
+
it "uses options" do
|
45
|
+
expect(test_class.validations.to_a).to eq [:foo]
|
46
|
+
expect(test_class.validations.set(:baz).to_a).to eq [:foo]
|
47
|
+
expect(test_class.validations.set(:bar).to_a).to eq []
|
48
|
+
end
|
49
|
+
|
50
|
+
end # context
|
51
|
+
|
52
|
+
end # describe .validate
|
53
|
+
|
54
|
+
describe "#validate" do
|
55
|
+
|
56
|
+
before do
|
57
|
+
test_class.validate :foo
|
58
|
+
test_class.validate :bar, only: :all
|
59
|
+
test_class.validate :baz, only: :foo
|
60
|
+
%i(foo bar baz).each { |method| allow(subject).to receive(method) }
|
61
|
+
end
|
62
|
+
|
63
|
+
context "without an argument" do
|
64
|
+
|
65
|
+
it "calls validations for :all context" do
|
66
|
+
expect(subject).to receive(:foo)
|
67
|
+
expect(subject).to receive(:bar)
|
68
|
+
expect(subject).not_to receive(:baz)
|
69
|
+
subject.validate
|
70
|
+
end
|
71
|
+
|
72
|
+
end # context
|
73
|
+
|
74
|
+
context ":foo" do
|
75
|
+
|
76
|
+
it "calls validations for :foo context" do
|
77
|
+
expect(subject).to receive(:foo)
|
78
|
+
expect(subject).to receive(:baz)
|
79
|
+
expect(subject).not_to receive(:bar)
|
80
|
+
subject.validate :foo
|
81
|
+
end
|
82
|
+
|
83
|
+
end # context
|
84
|
+
|
85
|
+
end # describe #validate
|
86
|
+
|
87
|
+
describe "#invalid" do
|
88
|
+
|
89
|
+
shared_examples "raising an error" do |name, options = {}|
|
90
|
+
|
91
|
+
let(:message) { message_class.new(name, subject, options) }
|
92
|
+
|
93
|
+
it "raises an InvalidError" do
|
94
|
+
expect { invalid }.to raise_error invalid_error
|
95
|
+
end
|
96
|
+
|
97
|
+
it "assings itself to the exception" do
|
98
|
+
begin
|
99
|
+
invalid
|
100
|
+
rescue => error
|
101
|
+
expect(error.object).to eq subject
|
102
|
+
expect(error.messages).to contain_exactly message
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end # shared examples
|
107
|
+
|
108
|
+
context "without options" do
|
109
|
+
|
110
|
+
let(:invalid) { subject.invalid :foo }
|
111
|
+
|
112
|
+
it_behaves_like "raising an error", :foo
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
context "with options" do
|
117
|
+
|
118
|
+
let(:invalid) { subject.invalid :foo, bar: :baz }
|
119
|
+
|
120
|
+
it_behaves_like "raising an error", :foo, bar: :baz
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end # invalid
|
125
|
+
|
126
|
+
end # describe Attestor::Validations
|