shoulda-matchers 1.3.0 → 1.4.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.
- data/.travis.yml +1 -0
- data/Appraisals +3 -3
- data/Gemfile.lock +2 -2
- data/NEWS.md +20 -0
- data/README.md +1 -1
- data/gemfiles/3.0.gemfile +1 -1
- data/gemfiles/3.0.gemfile.lock +27 -27
- data/gemfiles/3.1.gemfile +1 -1
- data/gemfiles/3.1.gemfile.lock +36 -36
- data/gemfiles/3.2.gemfile +1 -1
- data/gemfiles/3.2.gemfile.lock +35 -35
- data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +4 -1
- data/lib/shoulda/matchers/active_model.rb +14 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +45 -21
- data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +28 -6
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +22 -4
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +1 -0
- data/lib/shoulda/matchers/active_model/errors.rb +7 -0
- data/lib/shoulda/matchers/active_model/exception_message_finder.rb +58 -0
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +9 -1
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +27 -8
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +69 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +14 -5
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +8 -5
- data/lib/shoulda/matchers/version.rb +1 -1
- data/shoulda-matchers.gemspec +1 -1
- data/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb +6 -0
- data/spec/shoulda/active_model/allow_value_matcher_spec.rb +32 -0
- data/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb +23 -1
- data/spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb +49 -0
- data/spec/shoulda/active_model/ensure_length_of_matcher_spec.rb +13 -0
- data/spec/shoulda/active_model/exception_message_finder_spec.rb +112 -0
- data/spec/shoulda/active_model/validate_presence_of_matcher_spec.rb +15 -0
- data/spec/shoulda/active_model/validation_message_finder_spec.rb +107 -0
- data/spec/shoulda/active_record/association_matcher_spec.rb +8 -0
- data/spec/shoulda/active_record/have_db_index_matcher_spec.rb +17 -0
- metadata +18 -6
@@ -0,0 +1,69 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveModel
|
4
|
+
|
5
|
+
# Finds message information from a model's #errors method.
|
6
|
+
class ValidationMessageFinder
|
7
|
+
include Helpers
|
8
|
+
|
9
|
+
def initialize(instance, attribute)
|
10
|
+
@instance = instance
|
11
|
+
@attribute = attribute
|
12
|
+
end
|
13
|
+
|
14
|
+
def allow_description(allowed_values)
|
15
|
+
"allow #{@attribute} to be set to #{allowed_values}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def expected_message_from(attribute_message)
|
19
|
+
attribute_message
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_messages?
|
23
|
+
errors.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def source_description
|
27
|
+
'errors'
|
28
|
+
end
|
29
|
+
|
30
|
+
def messages_description
|
31
|
+
if errors.empty?
|
32
|
+
"no errors"
|
33
|
+
else
|
34
|
+
"errors: #{pretty_error_messages(validated_instance)}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def messages
|
39
|
+
Array.wrap(messages_for_attribute)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def messages_for_attribute
|
45
|
+
if errors.respond_to?(:[])
|
46
|
+
errors[@attribute]
|
47
|
+
else
|
48
|
+
errors.on(@attribute)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def errors
|
53
|
+
validated_instance.errors
|
54
|
+
end
|
55
|
+
|
56
|
+
def validated_instance
|
57
|
+
@validated_instance ||= validate_instance
|
58
|
+
end
|
59
|
+
|
60
|
+
def validate_instance
|
61
|
+
@instance.valid?
|
62
|
+
@instance
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -100,6 +100,11 @@ module Shoulda # :nodoc:
|
|
100
100
|
self
|
101
101
|
end
|
102
102
|
|
103
|
+
def with_foreign_key(foreign_key)
|
104
|
+
@options[:foreign_key] = foreign_key
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
103
108
|
def validate(validate = true)
|
104
109
|
@validate = validate
|
105
110
|
self
|
@@ -243,7 +248,7 @@ module Shoulda # :nodoc:
|
|
243
248
|
|
244
249
|
def join_table_exists?
|
245
250
|
if @macro != :has_and_belongs_to_many ||
|
246
|
-
|
251
|
+
model_class.connection.tables.include?(join_table)
|
247
252
|
true
|
248
253
|
else
|
249
254
|
@missing = "join table #{join_table} doesn't exist"
|
@@ -261,11 +266,15 @@ module Shoulda # :nodoc:
|
|
261
266
|
end
|
262
267
|
|
263
268
|
def class_has_foreign_key?(klass)
|
264
|
-
if
|
265
|
-
|
269
|
+
if @options.key?(:foreign_key)
|
270
|
+
reflection.options[:foreign_key] == @options[:foreign_key]
|
266
271
|
else
|
267
|
-
|
268
|
-
|
272
|
+
if klass.column_names.include?(foreign_key)
|
273
|
+
true
|
274
|
+
else
|
275
|
+
@missing = "#{klass} does not have a #{foreign_key} foreign key."
|
276
|
+
false
|
277
|
+
end
|
269
278
|
end
|
270
279
|
end
|
271
280
|
|
@@ -62,13 +62,16 @@ module Shoulda # :nodoc:
|
|
62
62
|
def correct_unique?
|
63
63
|
return true unless @options.key?(:unique)
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
is_unique = matched_index.unique
|
66
|
+
|
67
|
+
is_unique = !is_unique unless @options[:unique]
|
68
|
+
|
69
|
+
unless is_unique
|
68
70
|
@missing = "#{table_name} has an index named #{matched_index.name} " <<
|
69
|
-
|
70
|
-
false
|
71
|
+
"of unique #{matched_index.unique}, not #{@options[:unique]}."
|
71
72
|
end
|
73
|
+
|
74
|
+
is_unique
|
72
75
|
end
|
73
76
|
|
74
77
|
def matched_index
|
data/shoulda-matchers.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_development_dependency('appraisal', '~> 0.4.0')
|
23
23
|
s.add_development_dependency('aruba')
|
24
24
|
s.add_development_dependency('bourne', '~> 1.1.2')
|
25
|
-
s.add_development_dependency('bundler', '~> 1.1
|
25
|
+
s.add_development_dependency('bundler', '~> 1.1')
|
26
26
|
s.add_development_dependency('cucumber', '~> 1.1.9')
|
27
27
|
s.add_development_dependency('rails', '~> 3.0')
|
28
28
|
s.add_development_dependency('rake', '~> 0.9.2')
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Shoulda::Matchers::ActionController::SetTheFlashMatcher do
|
4
|
+
it "should fail with unmatchable to" do
|
5
|
+
expect{
|
6
|
+
set_the_flash.to(1).should
|
7
|
+
}.to raise_error("cannot match against 1")
|
8
|
+
end
|
9
|
+
|
4
10
|
context "a controller that sets a flash message" do
|
5
11
|
let(:controller) { build_response { flash[:notice] = 'value' } }
|
6
12
|
|
@@ -88,4 +88,36 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher do
|
|
88
88
|
end.should raise_error(ArgumentError, /at least one argument/)
|
89
89
|
end
|
90
90
|
end
|
91
|
+
|
92
|
+
if Rails::VERSION::STRING.to_f >= 3.2
|
93
|
+
context "an attribute with a strict format validation" do
|
94
|
+
let(:model) do
|
95
|
+
define_model :example, :attr => :string do
|
96
|
+
validates_format_of :attr, :with => /abc/, :strict => true
|
97
|
+
end.new
|
98
|
+
end
|
99
|
+
|
100
|
+
it "strictly rejects a bad value" do
|
101
|
+
model.should_not allow_value("xyz").for(:attr).strict
|
102
|
+
end
|
103
|
+
|
104
|
+
it "strictly allows a bad value with a different message" do
|
105
|
+
model.should allow_value("xyz").for(:attr).with_message(/abc/).strict
|
106
|
+
end
|
107
|
+
|
108
|
+
it "describes itself" do
|
109
|
+
allow_value("xyz").for(:attr).strict.description.
|
110
|
+
should == %{doesn't raise when attr is set to "xyz"}
|
111
|
+
end
|
112
|
+
|
113
|
+
it "provides a useful negative failure message" do
|
114
|
+
matcher = allow_value("xyz").for(:attr).strict.with_message(/abc/)
|
115
|
+
matcher.matches?(model)
|
116
|
+
matcher.negative_failure_message.
|
117
|
+
should == 'Expected exception to include /abc/ ' +
|
118
|
+
'when attr is set to "xyz", got Attr is invalid'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
91
123
|
end
|
@@ -51,7 +51,29 @@ describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do
|
|
51
51
|
it "should accept ensuring the correct range and messages" do
|
52
52
|
@model.should ensure_exclusion_of(:attr).in_range(2..5).with_message(/shoud be out of this range/)
|
53
53
|
end
|
54
|
-
|
55
54
|
end
|
56
55
|
|
56
|
+
context "an attribute which must be excluded in an array" do
|
57
|
+
before do
|
58
|
+
@model = define_model(:example, :attr => :string) do
|
59
|
+
validates_exclusion_of :attr, :in => %w(one two)
|
60
|
+
end.new
|
61
|
+
end
|
62
|
+
|
63
|
+
it "accepts with correct array" do
|
64
|
+
@model.should ensure_exclusion_of(:attr).in_array(%w(one two))
|
65
|
+
end
|
66
|
+
|
67
|
+
it "rejects when only part of array matches" do
|
68
|
+
@model.should_not ensure_exclusion_of(:attr).in_array(%w(one wrong_value))
|
69
|
+
end
|
70
|
+
|
71
|
+
it "rejects when array doesn't match at all" do
|
72
|
+
@model.should_not ensure_exclusion_of(:attr).in_array(%w(cat dog))
|
73
|
+
end
|
74
|
+
|
75
|
+
it "has correct description" do
|
76
|
+
ensure_exclusion_of(:attr).in_array([true, 'dog']).description.should == 'ensure exclusion of attr in [true, "dog"]'
|
77
|
+
end
|
78
|
+
end
|
57
79
|
end
|
@@ -1,6 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Shoulda::Matchers::ActiveModel::EnsureInclusionOfMatcher do
|
4
|
+
context "with no validations" do
|
5
|
+
before do
|
6
|
+
@model = define_model(:example, :attr => :string) do
|
7
|
+
end.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should reject an array which does not have a validator defined" do
|
11
|
+
@model.should_not ensure_inclusion_of(:attr).in_array(%w(Yes No))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "where we cannot determine a value outside the array" do
|
16
|
+
it "should raise a custom exception" do
|
17
|
+
@model = define_model(:example, :attr => :string).new
|
18
|
+
|
19
|
+
expect { @model.should ensure_inclusion_of(:attr).in_array([""]) }.to raise_error Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray
|
20
|
+
end
|
21
|
+
end
|
4
22
|
|
5
23
|
context "an attribute which must be included in a range" do
|
6
24
|
before do
|
@@ -120,4 +138,35 @@ describe Shoulda::Matchers::ActiveModel::EnsureInclusionOfMatcher do
|
|
120
138
|
@model.should_not ensure_inclusion_of(:attr).in_array(['one', 'two']).allow_nil(false)
|
121
139
|
end
|
122
140
|
end
|
141
|
+
|
142
|
+
context "an attribute allowing some blank values but not others" do
|
143
|
+
before do
|
144
|
+
@model = define_model(:example, :attr => :string) do
|
145
|
+
validates_inclusion_of :attr, :in => ['one', 'two', '']
|
146
|
+
end.new
|
147
|
+
end
|
148
|
+
|
149
|
+
it "rejects allow_blank" do
|
150
|
+
@model.should_not ensure_inclusion_of(:attr).in_array(['one', 'two', '']).allow_blank(true)
|
151
|
+
@model.should ensure_inclusion_of(:attr).in_array(['one', 'two', '']).allow_blank(false)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
if Rails::VERSION::STRING.to_f >= 3.2
|
156
|
+
context "a strict attribute which must be included in a range" do
|
157
|
+
before do
|
158
|
+
@model = define_model(:example, :attr => :integer) do
|
159
|
+
validates_inclusion_of :attr, :in => 2..5, :strict => true
|
160
|
+
end.new
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should accept ensuring the correct range" do
|
164
|
+
@model.should ensure_inclusion_of(:attr).in_range(2..5).strict
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should not accept ensuring another range" do
|
168
|
+
@model.should_not ensure_inclusion_of(:attr).in_range(2..6).strict
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
123
172
|
end
|
@@ -86,6 +86,19 @@ describe Shoulda::Matchers::ActiveModel::EnsureLengthOfMatcher do
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
context "an attribute with a required exact length and another validation" do
|
90
|
+
before do
|
91
|
+
@model = define_model(:example, :attr => :string) do
|
92
|
+
validates_length_of :attr, :is => 4
|
93
|
+
validates_numericality_of :attr
|
94
|
+
end.new
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should accept ensuring the correct length" do
|
98
|
+
@model.should ensure_length_of(:attr).is_equal_to(4)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
89
102
|
context "an attribute with a custom minimum length validation" do
|
90
103
|
before do
|
91
104
|
@model = define_model(:example, :attr => :string) do
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shoulda::Matchers::ActiveModel::ExceptionMessageFinder do
|
4
|
+
if Rails::VERSION::STRING.to_f >= 3.2
|
5
|
+
context '#allow_description' do
|
6
|
+
it 'describes its attribute' do
|
7
|
+
finder = build_finder(:attribute => :attr)
|
8
|
+
|
9
|
+
description = finder.allow_description('allowed values')
|
10
|
+
|
11
|
+
description.should == "doesn't raise when attr is set to allowed values"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context '#expected_message_from' do
|
16
|
+
it 'returns the message with the attribute name prefixed' do
|
17
|
+
finder = build_finder(:attribute => :attr)
|
18
|
+
|
19
|
+
message = finder.expected_message_from('some message')
|
20
|
+
|
21
|
+
message.should == 'Attr some message'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context '#has_messages?' do
|
26
|
+
it 'has messages when some validations fail' do
|
27
|
+
finder = build_finder(:format => /abc/, :value => 'xyz')
|
28
|
+
|
29
|
+
result = finder.has_messages?
|
30
|
+
|
31
|
+
result.should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'has no messages when all validations pass' do
|
35
|
+
finder = build_finder(:format => /abc/, :value => 'abc')
|
36
|
+
|
37
|
+
result = finder.has_messages?
|
38
|
+
|
39
|
+
result.should be_false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context '#messages' do
|
44
|
+
it 'returns errors for the given attribute' do
|
45
|
+
finder = build_finder(
|
46
|
+
:attribute => :attr,
|
47
|
+
:format => /abc/,
|
48
|
+
:value => 'xyz'
|
49
|
+
)
|
50
|
+
|
51
|
+
messages = finder.messages
|
52
|
+
|
53
|
+
messages.should == ['Attr is invalid']
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context '#messages_description' do
|
58
|
+
it 'describes errors for the given attribute' do
|
59
|
+
finder = build_finder(
|
60
|
+
:attribute => :attr,
|
61
|
+
:format => /abc/,
|
62
|
+
:value => 'xyz'
|
63
|
+
)
|
64
|
+
|
65
|
+
description = finder.messages_description
|
66
|
+
|
67
|
+
description.should == 'Attr is invalid'
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'describes errors when there are none' do
|
71
|
+
finder = build_finder(:format => /abc/, :value => 'abc')
|
72
|
+
|
73
|
+
description = finder.messages_description
|
74
|
+
|
75
|
+
description.should == 'no exception'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context '#source_description' do
|
80
|
+
it 'describes the source of its messages' do
|
81
|
+
finder = build_finder
|
82
|
+
|
83
|
+
description = finder.source_description
|
84
|
+
|
85
|
+
description.should == 'exception'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def build_finder(arguments = {})
|
91
|
+
arguments[:attribute] ||= :attr
|
92
|
+
instance = build_instance_validating(
|
93
|
+
arguments[:attribute],
|
94
|
+
arguments[:format] || /abc/,
|
95
|
+
arguments[:value] || 'abc'
|
96
|
+
)
|
97
|
+
Shoulda::Matchers::ActiveModel::ExceptionMessageFinder.new(
|
98
|
+
instance,
|
99
|
+
arguments[:attribute]
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def build_instance_validating(attribute, format, value)
|
104
|
+
model_class = define_model(:example, attribute => :string) do
|
105
|
+
attr_accessible attribute
|
106
|
+
validates_format_of attribute, :with => format, :strict => true
|
107
|
+
end
|
108
|
+
|
109
|
+
model_class.new(attribute => value)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
@@ -117,4 +117,19 @@ describe Shoulda::Matchers::ActiveModel::ValidatePresenceOfMatcher do
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
+
if Rails::VERSION::STRING.to_f >= 3.2
|
121
|
+
context "a strictly required attribute" do
|
122
|
+
before do
|
123
|
+
define_model :example, :attr => :string do
|
124
|
+
validates_presence_of :attr, :strict => true
|
125
|
+
end
|
126
|
+
@model = Example.new
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should require a value" do
|
130
|
+
@model.should validate_presence_of(:attr).strict
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
120
135
|
end
|