shoulda-activemodel 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/shoulda/active_model.rb +16 -0
- data/lib/shoulda/active_model/assertions.rb +61 -0
- data/lib/shoulda/active_model/helpers.rb +31 -0
- data/lib/shoulda/active_model/macros.rb +268 -0
- data/lib/shoulda/active_model/matchers.rb +30 -0
- data/lib/shoulda/active_model/matchers/allow_value_matcher.rb +102 -0
- data/lib/shoulda/active_model/matchers/ensure_inclusion_of_matcher.rb +87 -0
- data/lib/shoulda/active_model/matchers/ensure_length_of_matcher.rb +141 -0
- data/lib/shoulda/active_model/matchers/validate_acceptance_of_matcher.rb +41 -0
- data/lib/shoulda/active_model/matchers/validate_format_of_matcher.rb +67 -0
- data/lib/shoulda/active_model/matchers/validate_numericality_of_matcher.rb +39 -0
- data/lib/shoulda/active_model/matchers/validate_presence_of_matcher.rb +60 -0
- data/lib/shoulda/active_model/matchers/validate_uniqueness_of_matcher.rb +148 -0
- data/lib/shoulda/active_model/matchers/validation_matcher.rb +57 -0
- data/test/fail_macros.rb +39 -0
- data/test/matchers/active_model/ensure_inclusion_of_matcher_test.rb +80 -0
- data/test/matchers/active_model/ensure_length_of_matcher_test.rb +158 -0
- data/test/matchers/active_model/validate_acceptance_of_matcher_test.rb +44 -0
- data/test/matchers/active_model/validate_format_of_matcher_test.rb +39 -0
- data/test/matchers/active_model/validate_numericality_of_matcher_test.rb +52 -0
- data/test/matchers/active_model/validate_presence_of_matcher_test.rb +86 -0
- data/test/matchers/active_model/validate_uniqueness_of_matcher_test.rb +147 -0
- data/test/model_builder.rb +106 -0
- data/test/rspec_test.rb +207 -0
- data/test/test_helper.rb +20 -0
- metadata +106 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
module Shoulda # :nodoc:
|
2
|
+
module ActiveModel # :nodoc:
|
3
|
+
module Matchers
|
4
|
+
|
5
|
+
class ValidationMatcher # :nodoc:
|
6
|
+
|
7
|
+
attr_reader :failure_message
|
8
|
+
|
9
|
+
def initialize(attribute)
|
10
|
+
@attribute = attribute
|
11
|
+
end
|
12
|
+
|
13
|
+
def negative_failure_message
|
14
|
+
@negative_failure_message || @failure_message
|
15
|
+
end
|
16
|
+
|
17
|
+
def matches?(subject)
|
18
|
+
@subject = subject
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def allows_value_of(value, message = nil)
|
26
|
+
allow = AllowValueMatcher.
|
27
|
+
new(value).
|
28
|
+
for(@attribute).
|
29
|
+
with_message(message)
|
30
|
+
if allow.matches?(@subject)
|
31
|
+
@negative_failure_message = allow.failure_message
|
32
|
+
true
|
33
|
+
else
|
34
|
+
@failure_message = allow.negative_failure_message
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def disallows_value_of(value, message = nil)
|
40
|
+
disallow = AllowValueMatcher.
|
41
|
+
new(value).
|
42
|
+
for(@attribute).
|
43
|
+
with_message(message)
|
44
|
+
if disallow.matches?(@subject)
|
45
|
+
@failure_message = disallow.negative_failure_message
|
46
|
+
false
|
47
|
+
else
|
48
|
+
@negative_failure_message = disallow.failure_message
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
data/test/fail_macros.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Shoulda
|
2
|
+
class << self
|
3
|
+
attr_accessor :expected_exceptions
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
# Enables the core shoulda test suite to test for failure scenarios. For
|
8
|
+
# example, to ensure that a set of test macros should fail, do this:
|
9
|
+
#
|
10
|
+
# should_fail do
|
11
|
+
# should_validate_presence_of :comments
|
12
|
+
# should_not_allow_mass_assignment_of :name
|
13
|
+
# end
|
14
|
+
def should_fail(&block)
|
15
|
+
context "should fail when trying to run:" do
|
16
|
+
if defined?(Test::Unit::AssertionFailedError)
|
17
|
+
failures = [Test::Unit::AssertionFailedError]
|
18
|
+
elsif defined?(MiniTest::Assertion)
|
19
|
+
failures = [MiniTest::Assertion]
|
20
|
+
end
|
21
|
+
Shoulda.expected_exceptions = failures
|
22
|
+
yield block
|
23
|
+
Shoulda.expected_exceptions = nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Context
|
29
|
+
# alias_method_chain hack to allow the should_fail macro to work
|
30
|
+
def should_with_failure_scenario(name, options = {}, &block)
|
31
|
+
if Shoulda.expected_exceptions
|
32
|
+
expected_exceptions = Shoulda.expected_exceptions
|
33
|
+
failure_block = lambda { assert_raise(*expected_exceptions, &block.bind(self)) }
|
34
|
+
end
|
35
|
+
should_without_failure_scenario(name, options, &(failure_block || block))
|
36
|
+
end
|
37
|
+
alias_method_chain :should, :failure_scenario
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class EnsureInclusionOfMatcherTest < ActiveSupport::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "an attribute which must be included in a range" do
|
6
|
+
setup do
|
7
|
+
@model = define_model(:example, :attr => :integer) do
|
8
|
+
validates_inclusion_of :attr, :in => 2..5
|
9
|
+
end.new
|
10
|
+
end
|
11
|
+
|
12
|
+
should "accept ensuring the correct range" do
|
13
|
+
assert_accepts ensure_inclusion_of(:attr).in_range(2..5), @model
|
14
|
+
end
|
15
|
+
|
16
|
+
should "reject ensuring a lower minimum value" do
|
17
|
+
assert_rejects ensure_inclusion_of(:attr).in_range(1..5), @model
|
18
|
+
end
|
19
|
+
|
20
|
+
should "reject ensuring a higher minimum value" do
|
21
|
+
assert_rejects ensure_inclusion_of(:attr).in_range(3..5), @model
|
22
|
+
end
|
23
|
+
|
24
|
+
should "reject ensuring a lower maximum value" do
|
25
|
+
assert_rejects ensure_inclusion_of(:attr).in_range(2..4), @model
|
26
|
+
end
|
27
|
+
|
28
|
+
should "reject ensuring a higher maximum value" do
|
29
|
+
assert_rejects ensure_inclusion_of(:attr).in_range(2..6), @model
|
30
|
+
end
|
31
|
+
|
32
|
+
should "not override the default message with a blank" do
|
33
|
+
assert_accepts ensure_inclusion_of(:attr).
|
34
|
+
in_range(2..5).
|
35
|
+
with_message(nil),
|
36
|
+
@model
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "an attribute with a custom ranged value validation" do
|
41
|
+
setup do
|
42
|
+
@model = define_model(:example, :attr => :string) do
|
43
|
+
validates_inclusion_of :attr, :in => 2..4, :message => 'not good'
|
44
|
+
|
45
|
+
end.new
|
46
|
+
end
|
47
|
+
|
48
|
+
should "accept ensuring the correct range" do
|
49
|
+
assert_accepts ensure_inclusion_of(:attr).
|
50
|
+
in_range(2..4).
|
51
|
+
with_message(/not good/),
|
52
|
+
@model
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "an attribute with custom range validations" do
|
57
|
+
setup do
|
58
|
+
define_model :example, :attr => :integer do
|
59
|
+
def validate
|
60
|
+
if attr < 2
|
61
|
+
errors.add(:attr, 'too low')
|
62
|
+
elsif attr > 5
|
63
|
+
errors.add(:attr, 'too high')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@model = Example.new
|
68
|
+
end
|
69
|
+
|
70
|
+
should "accept ensuring the correct range and messages" do
|
71
|
+
assert_accepts ensure_inclusion_of(:attr).
|
72
|
+
in_range(2..5).
|
73
|
+
with_low_message(/low/).
|
74
|
+
with_high_message(/high/),
|
75
|
+
@model
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class EnsureLengthOfMatcher < ActiveSupport::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "an attribute with a non-zero minimum length validation" do
|
6
|
+
setup do
|
7
|
+
@model = define_model(:example, :attr => :string) do
|
8
|
+
validates_length_of :attr, :minimum => 4
|
9
|
+
end.new
|
10
|
+
end
|
11
|
+
|
12
|
+
should "accept ensuring the correct minimum length" do
|
13
|
+
assert_accepts ensure_length_of(:attr).is_at_least(4), @model
|
14
|
+
end
|
15
|
+
|
16
|
+
should "reject ensuring a lower minimum length with any message" do
|
17
|
+
assert_rejects ensure_length_of(:attr).
|
18
|
+
is_at_least(3).
|
19
|
+
with_short_message(/.*/),
|
20
|
+
@model
|
21
|
+
end
|
22
|
+
|
23
|
+
should "reject ensuring a higher minimum length with any message" do
|
24
|
+
assert_rejects ensure_length_of(:attr).
|
25
|
+
is_at_least(5).
|
26
|
+
with_short_message(/.*/),
|
27
|
+
@model
|
28
|
+
end
|
29
|
+
|
30
|
+
should "not override the default message with a blank" do
|
31
|
+
assert_accepts ensure_length_of(:attr).
|
32
|
+
is_at_least(4).
|
33
|
+
with_short_message(nil),
|
34
|
+
@model
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "an attribute with a minimum length validation of 0" do
|
39
|
+
setup do
|
40
|
+
@model = define_model(:example, :attr => :string) do
|
41
|
+
validates_length_of :attr, :minimum => 0
|
42
|
+
end.new
|
43
|
+
end
|
44
|
+
|
45
|
+
should "accept ensuring the correct minimum length" do
|
46
|
+
assert_accepts ensure_length_of(:attr).is_at_least(0), @model
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "an attribute with a maximum length" do
|
51
|
+
setup do
|
52
|
+
@model = define_model(:example, :attr => :string) do
|
53
|
+
validates_length_of :attr, :maximum => 4
|
54
|
+
end.new
|
55
|
+
end
|
56
|
+
|
57
|
+
should "accept ensuring the correct maximum length" do
|
58
|
+
assert_accepts ensure_length_of(:attr).is_at_most(4), @model
|
59
|
+
end
|
60
|
+
|
61
|
+
should "reject ensuring a lower maximum length with any message" do
|
62
|
+
assert_rejects ensure_length_of(:attr).
|
63
|
+
is_at_most(3).
|
64
|
+
with_long_message(/.*/),
|
65
|
+
@model
|
66
|
+
end
|
67
|
+
|
68
|
+
should "reject ensuring a higher maximum length with any message" do
|
69
|
+
assert_rejects ensure_length_of(:attr).
|
70
|
+
is_at_most(5).
|
71
|
+
with_long_message(/.*/),
|
72
|
+
@model
|
73
|
+
end
|
74
|
+
|
75
|
+
should "not override the default message with a blank" do
|
76
|
+
assert_accepts ensure_length_of(:attr).
|
77
|
+
is_at_most(4).
|
78
|
+
with_long_message(nil),
|
79
|
+
@model
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "an attribute with a required exact length" do
|
84
|
+
setup do
|
85
|
+
@model = define_model(:example, :attr => :string) do
|
86
|
+
validates_length_of :attr, :is => 4
|
87
|
+
end.new
|
88
|
+
end
|
89
|
+
|
90
|
+
should "accept ensuring the correct length" do
|
91
|
+
assert_accepts ensure_length_of(:attr).is_equal_to(4), @model
|
92
|
+
end
|
93
|
+
|
94
|
+
should "reject ensuring a lower maximum length with any message" do
|
95
|
+
assert_rejects ensure_length_of(:attr).
|
96
|
+
is_equal_to(3).
|
97
|
+
with_message(/.*/),
|
98
|
+
@model
|
99
|
+
end
|
100
|
+
|
101
|
+
should "reject ensuring a higher maximum length with any message" do
|
102
|
+
assert_rejects ensure_length_of(:attr).
|
103
|
+
is_equal_to(5).
|
104
|
+
with_message(/.*/),
|
105
|
+
@model
|
106
|
+
end
|
107
|
+
|
108
|
+
should "not override the default message with a blank" do
|
109
|
+
assert_accepts ensure_length_of(:attr).
|
110
|
+
is_equal_to(4).
|
111
|
+
with_message(nil),
|
112
|
+
@model
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "an attribute with a custom minimum length validation" do
|
117
|
+
setup do
|
118
|
+
@model = define_model(:example, :attr => :string) do
|
119
|
+
validates_length_of :attr, :minimum => 4, :too_short => 'short'
|
120
|
+
end.new
|
121
|
+
end
|
122
|
+
|
123
|
+
should "accept ensuring the correct minimum length" do
|
124
|
+
assert_accepts ensure_length_of(:attr).
|
125
|
+
is_at_least(4).
|
126
|
+
with_short_message(/short/),
|
127
|
+
@model
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
context "an attribute with a custom maximum length validation" do
|
133
|
+
setup do
|
134
|
+
@model = define_model(:example, :attr => :string) do
|
135
|
+
validates_length_of :attr, :maximum => 4, :too_long => 'long'
|
136
|
+
end.new
|
137
|
+
end
|
138
|
+
|
139
|
+
should "accept ensuring the correct minimum length" do
|
140
|
+
assert_accepts ensure_length_of(:attr).
|
141
|
+
is_at_most(4).
|
142
|
+
with_long_message(/long/),
|
143
|
+
@model
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
context "an attribute without a length validation" do
|
149
|
+
setup do
|
150
|
+
@model = define_model(:example, :attr => :string).new
|
151
|
+
end
|
152
|
+
|
153
|
+
should "reject ensuring a minimum length" do
|
154
|
+
assert_rejects ensure_length_of(:attr).is_at_least(1), @model
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class ValidateAcceptanceOfMatcherTest < ActiveSupport::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "an attribute which must be accepted" do
|
6
|
+
setup do
|
7
|
+
@model = define_model(:example) do
|
8
|
+
validates_acceptance_of :attr
|
9
|
+
end.new
|
10
|
+
end
|
11
|
+
|
12
|
+
should "require that attribute to be accepted" do
|
13
|
+
assert_accepts validate_acceptance_of(:attr), @model
|
14
|
+
end
|
15
|
+
|
16
|
+
should "not overwrite the default message with nil" do
|
17
|
+
assert_accepts validate_acceptance_of(:attr).with_message(nil), @model
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "an attribute that does not need to be accepted" do
|
22
|
+
setup do
|
23
|
+
@model = define_model(:example, :attr => :string).new
|
24
|
+
end
|
25
|
+
|
26
|
+
should "not require that attribute to be accepted" do
|
27
|
+
assert_rejects validate_acceptance_of(:attr), @model
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "an attribute which must be accepted with a custom message" do
|
32
|
+
setup do
|
33
|
+
@model = define_model(:example) do
|
34
|
+
validates_acceptance_of :attr, :message => 'custom'
|
35
|
+
end.new
|
36
|
+
end
|
37
|
+
|
38
|
+
should "require that attribute to be accepted with that message" do
|
39
|
+
assert_accepts validate_acceptance_of(:attr).with_message(/custom/),
|
40
|
+
@model
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class ValidateFormatOfMatcherTest < ActiveSupport::TestCase # :nodoc:
|
4
|
+
|
5
|
+
|
6
|
+
context "a postal code" do
|
7
|
+
setup do
|
8
|
+
define_model :example, :attr => :string do
|
9
|
+
validates_format_of :attr, :with => /^\d{5}$/
|
10
|
+
end
|
11
|
+
@model = Example.new
|
12
|
+
end
|
13
|
+
|
14
|
+
should "be valid" do
|
15
|
+
assert_accepts validate_format_of(:attr).with('12345'), @model
|
16
|
+
end
|
17
|
+
|
18
|
+
should "not be valid with alpha in zip" do
|
19
|
+
assert_rejects validate_format_of(:attr).not_with('1234a'), @model, :message=>"is invalid"
|
20
|
+
end
|
21
|
+
|
22
|
+
should "not be valid with to few digits" do
|
23
|
+
assert_rejects validate_format_of(:attr).not_with('1234'), @model, :message=>"is invalid"
|
24
|
+
end
|
25
|
+
|
26
|
+
should "not be valid with to many digits" do
|
27
|
+
assert_rejects validate_format_of(:attr).not_with('123456'), @model, :message=>"is invalid"
|
28
|
+
end
|
29
|
+
|
30
|
+
should "raise error if you try to call both with and not_with" do
|
31
|
+
assert_raise RuntimeError do
|
32
|
+
validate_format_of(:attr).not_with('123456').with('12345')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class ValidateNumericalityOfMatcherTest < ActiveSupport::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "a numeric attribute" do
|
6
|
+
setup do
|
7
|
+
define_model :example, :attr => :string do
|
8
|
+
validates_numericality_of :attr
|
9
|
+
end
|
10
|
+
@model = Example.new
|
11
|
+
end
|
12
|
+
|
13
|
+
should "only allow numeric values for that attribute" do
|
14
|
+
assert_accepts validate_numericality_of(:attr), @model
|
15
|
+
end
|
16
|
+
|
17
|
+
should "not override the default message with a blank" do
|
18
|
+
assert_accepts validate_numericality_of(:attr).with_message(nil),
|
19
|
+
@model
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "a numeric attribute with a custom validation message" do
|
24
|
+
setup do
|
25
|
+
define_model :example, :attr => :string do
|
26
|
+
validates_numericality_of :attr, :message => 'custom'
|
27
|
+
end
|
28
|
+
@model = Example.new
|
29
|
+
end
|
30
|
+
|
31
|
+
should "only allow numeric values for that attribute with that message" do
|
32
|
+
assert_accepts validate_numericality_of(:attr).
|
33
|
+
with_message(/custom/),
|
34
|
+
@model
|
35
|
+
end
|
36
|
+
|
37
|
+
should "not allow numeric values for that attribute with another message" do
|
38
|
+
assert_rejects validate_numericality_of(:attr), @model
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "a non-numeric attribute" do
|
43
|
+
setup do
|
44
|
+
@model = define_model(:example, :attr => :string).new
|
45
|
+
end
|
46
|
+
|
47
|
+
should "not only allow numeric values for that attribute" do
|
48
|
+
assert_rejects validate_numericality_of(:attr), @model
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|