shoulda-matchers 2.6.2 → 2.7.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.
- checksums.yaml +4 -4
- data/Appraisals +6 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +26 -22
- data/NEWS.md +52 -1
- data/README.md +8 -6
- data/Rakefile +1 -1
- data/doc_config/gh-pages/index.html.erb +1 -1
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +1 -1
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +26 -0
- data/features/rails_integration.feature +18 -3
- data/features/step_definitions/rails_steps.rb +21 -3
- data/gemfiles/3.0.gemfile +1 -1
- data/gemfiles/3.0.gemfile.lock +30 -24
- data/gemfiles/3.1.gemfile +1 -1
- data/gemfiles/3.1.gemfile.lock +32 -26
- data/gemfiles/3.1_1.9.2.gemfile +1 -1
- data/gemfiles/3.1_1.9.2.gemfile.lock +22 -19
- data/gemfiles/3.2.gemfile +1 -1
- data/gemfiles/3.2.gemfile.lock +32 -26
- data/gemfiles/3.2_1.9.2.gemfile +1 -1
- data/gemfiles/3.2_1.9.2.gemfile.lock +8 -8
- data/gemfiles/4.0.0.gemfile +2 -2
- data/gemfiles/4.0.0.gemfile.lock +35 -31
- data/gemfiles/4.0.1.gemfile +2 -2
- data/gemfiles/4.0.1.gemfile.lock +24 -22
- data/gemfiles/4.1.gemfile +1 -1
- data/gemfiles/4.1.gemfile.lock +26 -22
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +10 -3
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +24 -6
- data/lib/shoulda/matchers/active_model.rb +2 -2
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +5 -3
- data/lib/shoulda/matchers/active_model/{ensure_exclusion_of_matcher.rb → validate_exclusion_of_matcher.rb} +20 -10
- data/lib/shoulda/matchers/active_model/{ensure_inclusion_of_matcher.rb → validate_inclusion_of_matcher.rb} +52 -28
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +28 -19
- data/lib/shoulda/matchers/active_record.rb +18 -16
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_record/association_matcher.rb +17 -12
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +86 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +19 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +2 -1
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +138 -0
- data/lib/shoulda/matchers/independent.rb +3 -2
- data/lib/shoulda/matchers/independent/{delegate_matcher.rb → delegate_method_matcher.rb} +69 -49
- data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +37 -0
- data/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +15 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers/warn.rb +30 -2
- data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +6 -0
- data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +67 -5
- data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +9 -9
- data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +30 -3
- data/spec/shoulda/matchers/active_model/{ensure_exclusion_of_matcher_spec.rb → validate_exclusion_of_matcher_spec.rb} +29 -13
- data/spec/shoulda/matchers/active_model/{ensure_inclusion_of_matcher_spec.rb → validate_inclusion_of_matcher_spec.rb} +34 -16
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +35 -0
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +56 -1
- data/spec/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +101 -0
- data/spec/shoulda/matchers/doublespeak/object_double_spec.rb +6 -6
- data/spec/shoulda/matchers/independent/{delegate_matcher → delegate_method_matcher}/stubbed_target_spec.rb +1 -1
- data/spec/shoulda/matchers/independent/{delegate_matcher_spec.rb → delegate_method_matcher_spec.rb} +88 -29
- data/spec/spec_helper.rb +2 -3
- data/spec/support/fail_with_message_including_matcher.rb +14 -3
- data/spec/support/fail_with_message_matcher.rb +14 -2
- data/spec/support/rails_versions.rb +4 -0
- metadata +19 -14
- data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +0 -35
@@ -28,7 +28,7 @@ module Shoulda
|
|
28
28
|
# @private
|
29
29
|
class FilterParamMatcher
|
30
30
|
def initialize(key)
|
31
|
-
@key = key
|
31
|
+
@key = key
|
32
32
|
end
|
33
33
|
|
34
34
|
def matches?(controller)
|
@@ -52,11 +52,18 @@ module Shoulda
|
|
52
52
|
private
|
53
53
|
|
54
54
|
def filters_key?
|
55
|
-
filtered_keys.
|
55
|
+
filtered_keys.any? do |filter|
|
56
|
+
case filter
|
57
|
+
when Regexp
|
58
|
+
filter =~ @key
|
59
|
+
else
|
60
|
+
filter == @key
|
61
|
+
end
|
62
|
+
end
|
56
63
|
end
|
57
64
|
|
58
65
|
def filtered_keys
|
59
|
-
Rails.application.config.filter_parameters
|
66
|
+
Rails.application.config.filter_parameters
|
60
67
|
end
|
61
68
|
end
|
62
69
|
end
|
@@ -38,28 +38,46 @@ module Shoulda
|
|
38
38
|
# particular value.
|
39
39
|
#
|
40
40
|
# class PostsController < ApplicationController
|
41
|
-
# def
|
41
|
+
# def index
|
42
42
|
# session[:foo] = 'bar'
|
43
43
|
# end
|
44
|
+
#
|
45
|
+
# def show
|
46
|
+
# session[:foo] = nil
|
47
|
+
# end
|
44
48
|
# end
|
45
49
|
#
|
46
50
|
# # RSpec
|
47
51
|
# describe PostsController do
|
48
|
-
# describe 'GET #
|
49
|
-
# before { get :
|
52
|
+
# describe 'GET #index' do
|
53
|
+
# before { get :index }
|
50
54
|
#
|
51
55
|
# it { should set_session(:foo).to('bar') }
|
52
56
|
# it { should_not set_session(:foo).to('something else') }
|
57
|
+
# it { should_not set_session(:foo).to(nil) }
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# describe 'GET #show' do
|
61
|
+
# before { get :show }
|
62
|
+
#
|
63
|
+
# it { should set_session(:foo).to(nil) }
|
53
64
|
# end
|
54
65
|
# end
|
55
66
|
#
|
56
67
|
# # Test::Unit
|
57
68
|
# class PostsControllerTest < ActionController::TestCase
|
58
|
-
# context 'GET #
|
59
|
-
# setup { get :
|
69
|
+
# context 'GET #index' do
|
70
|
+
# setup { get :index }
|
60
71
|
#
|
61
72
|
# should set_session(:foo).to('bar')
|
62
73
|
# should_not set_session(:foo).to('something else')
|
74
|
+
# should_not set_session(:foo).to(nil)
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# context 'GET #show' do
|
78
|
+
# setup { get :show }
|
79
|
+
#
|
80
|
+
# should set_session(:foo).to(nil)
|
63
81
|
# end
|
64
82
|
# end
|
65
83
|
#
|
@@ -129,7 +147,7 @@ module Shoulda
|
|
129
147
|
|
130
148
|
def assigned_correct_value?
|
131
149
|
if assigned_value?
|
132
|
-
if
|
150
|
+
if !defined?(@value)
|
133
151
|
true
|
134
152
|
else
|
135
153
|
assigned_value == value_or_default_value
|
@@ -5,8 +5,8 @@ require 'shoulda/matchers/active_model/exception_message_finder'
|
|
5
5
|
require 'shoulda/matchers/active_model/allow_value_matcher'
|
6
6
|
require 'shoulda/matchers/active_model/disallow_value_matcher'
|
7
7
|
require 'shoulda/matchers/active_model/ensure_length_of_matcher'
|
8
|
-
require 'shoulda/matchers/active_model/
|
9
|
-
require 'shoulda/matchers/active_model/
|
8
|
+
require 'shoulda/matchers/active_model/validate_inclusion_of_matcher'
|
9
|
+
require 'shoulda/matchers/active_model/validate_exclusion_of_matcher'
|
10
10
|
require 'shoulda/matchers/active_model/validate_absence_of_matcher'
|
11
11
|
require 'shoulda/matchers/active_model/validate_presence_of_matcher'
|
12
12
|
require 'shoulda/matchers/active_model/validate_uniqueness_of_matcher'
|
@@ -57,7 +57,7 @@ module Shoulda
|
|
57
57
|
#
|
58
58
|
# ##### is_equal_to
|
59
59
|
#
|
60
|
-
# Use `
|
60
|
+
# Use `is_equal_to` to test usage of the `:is` option. This asserts that
|
61
61
|
# the attribute can take a string which is exactly equal to the given
|
62
62
|
# length and cannot take a string which is shorter or longer.
|
63
63
|
#
|
@@ -82,8 +82,10 @@ module Shoulda
|
|
82
82
|
else
|
83
83
|
obj
|
84
84
|
end
|
85
|
-
elsif attribute_class
|
85
|
+
elsif [Fixnum, Float].include?(attribute_class)
|
86
86
|
1
|
87
|
+
elsif attribute_class == BigDecimal
|
88
|
+
BigDecimal.new(1, 0)
|
87
89
|
elsif !attribute_class || attribute_class == String
|
88
90
|
'an arbitrary value'
|
89
91
|
else
|
@@ -93,8 +95,8 @@ module Shoulda
|
|
93
95
|
|
94
96
|
def attribute_class
|
95
97
|
@subject.class.respond_to?(:columns_hash) &&
|
96
|
-
@subject.class.columns_hash[@attribute].respond_to?(:klass) &&
|
97
|
-
@subject.class.columns_hash[@attribute].klass
|
98
|
+
@subject.class.columns_hash[@attribute.to_s].respond_to?(:klass) &&
|
99
|
+
@subject.class.columns_hash[@attribute.to_s].klass
|
98
100
|
end
|
99
101
|
|
100
102
|
def collection?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Shoulda
|
2
2
|
module Matchers
|
3
3
|
module ActiveModel
|
4
|
-
# The `
|
4
|
+
# The `validate_exclusion_of` matcher tests usage of the
|
5
5
|
# `validates_exclusion_of` validation, asserting that an attribute cannot
|
6
6
|
# take a blacklist of values, and inversely, can take values outside of
|
7
7
|
# this list.
|
@@ -18,14 +18,14 @@ module Shoulda
|
|
18
18
|
# # RSpec
|
19
19
|
# describe Game do
|
20
20
|
# it do
|
21
|
-
# should
|
21
|
+
# should validate_exclusion_of(:supported_os).
|
22
22
|
# in_array(['Mac', 'Linux'])
|
23
23
|
# end
|
24
24
|
# end
|
25
25
|
#
|
26
26
|
# # Test::Unit
|
27
27
|
# class GameTest < ActiveSupport::TestCase
|
28
|
-
# should
|
28
|
+
# should validate_exclusion_of(:supported_os).
|
29
29
|
# in_array(['Mac', 'Linux'])
|
30
30
|
# end
|
31
31
|
#
|
@@ -41,14 +41,14 @@ module Shoulda
|
|
41
41
|
# # RSpec
|
42
42
|
# describe Game do
|
43
43
|
# it do
|
44
|
-
# should
|
44
|
+
# should validate_exclusion_of(:floors_with_enemies).
|
45
45
|
# in_range(5..8)
|
46
46
|
# end
|
47
47
|
# end
|
48
48
|
#
|
49
49
|
# # Test::Unit
|
50
50
|
# class GameTest < ActiveSupport::TestCase
|
51
|
-
# should
|
51
|
+
# should validate_exclusion_of(:floors_with_enemies).
|
52
52
|
# in_range(5..8)
|
53
53
|
# end
|
54
54
|
#
|
@@ -70,7 +70,7 @@ module Shoulda
|
|
70
70
|
# # RSpec
|
71
71
|
# describe Game do
|
72
72
|
# it do
|
73
|
-
# should
|
73
|
+
# should validate_exclusion_of(:weapon).
|
74
74
|
# in_array(['pistol', 'paintball gun', 'stick']).
|
75
75
|
# with_message('You chose a puny weapon')
|
76
76
|
# end
|
@@ -78,19 +78,29 @@ module Shoulda
|
|
78
78
|
#
|
79
79
|
# # Test::Unit
|
80
80
|
# class GameTest < ActiveSupport::TestCase
|
81
|
-
# should
|
81
|
+
# should validate_exclusion_of(:weapon).
|
82
82
|
# in_array(['pistol', 'paintball gun', 'stick']).
|
83
83
|
# with_message('You chose a puny weapon')
|
84
84
|
# end
|
85
85
|
#
|
86
|
-
# @return [
|
86
|
+
# @return [ValidateExclusionOfMatcher]
|
87
87
|
#
|
88
|
+
def validate_exclusion_of(attr)
|
89
|
+
ValidateExclusionOfMatcher.new(attr)
|
90
|
+
end
|
91
|
+
|
92
|
+
# @deprecated Use {#validate_exclusion_of} instead.
|
93
|
+
# @return [ValidateExclusionOfMatcher]
|
88
94
|
def ensure_exclusion_of(attr)
|
89
|
-
|
95
|
+
Shoulda::Matchers.warn_about_deprecated_method(
|
96
|
+
:ensure_exclusion_of,
|
97
|
+
:validate_exclusion_of
|
98
|
+
)
|
99
|
+
validate_exclusion_of(attr)
|
90
100
|
end
|
91
101
|
|
92
102
|
# @private
|
93
|
-
class
|
103
|
+
class ValidateExclusionOfMatcher < ValidationMatcher
|
94
104
|
def initialize(attribute)
|
95
105
|
super(attribute)
|
96
106
|
@array = nil
|
@@ -3,7 +3,7 @@ require 'bigdecimal'
|
|
3
3
|
module Shoulda
|
4
4
|
module Matchers
|
5
5
|
module ActiveModel
|
6
|
-
# The `
|
6
|
+
# The `validate_inclusion_of` matcher tests usage of the
|
7
7
|
# `validates_inclusion_of` validation, asserting that an attribute can
|
8
8
|
# take a whitelist of values and cannot take values outside of this list.
|
9
9
|
#
|
@@ -19,14 +19,14 @@ module Shoulda
|
|
19
19
|
# # RSpec
|
20
20
|
# describe Issue do
|
21
21
|
# it do
|
22
|
-
# should
|
22
|
+
# should validate_inclusion_of(:state).
|
23
23
|
# in_array(%w(open resolved unresolved))
|
24
24
|
# end
|
25
25
|
# end
|
26
26
|
#
|
27
27
|
# # Test::Unit
|
28
28
|
# class IssueTest < ActiveSupport::TestCase
|
29
|
-
# should
|
29
|
+
# should validate_inclusion_of(:state).
|
30
30
|
# in_array(%w(open resolved unresolved))
|
31
31
|
# end
|
32
32
|
#
|
@@ -41,15 +41,31 @@ module Shoulda
|
|
41
41
|
#
|
42
42
|
# # RSpec
|
43
43
|
# describe Issue do
|
44
|
-
# it { should
|
44
|
+
# it { should validate_inclusion_of(:state).in_range(1..5) }
|
45
45
|
# end
|
46
46
|
#
|
47
47
|
# # Test::Unit
|
48
48
|
# class IssueTest < ActiveSupport::TestCase
|
49
|
-
# should
|
49
|
+
# should validate_inclusion_of(:state).in_range(1..5)
|
50
50
|
# end
|
51
51
|
#
|
52
|
-
# ####
|
52
|
+
# #### Caveats
|
53
|
+
#
|
54
|
+
# We discourage using `validate_inclusion_of` with boolean columns. In
|
55
|
+
# fact, there is never a case where a boolean column will be anything but
|
56
|
+
# true, false, or nil, as ActiveRecord will type-cast an incoming value to
|
57
|
+
# one of these three values. That means there isn't any way we can refute
|
58
|
+
# this logic in a test. Hence, this will produce a warning:
|
59
|
+
#
|
60
|
+
# it { should validate_inclusion_of(:imported).in_array([true, false]) }
|
61
|
+
#
|
62
|
+
# The only case where `validate_inclusion_of` *could* be appropriate is
|
63
|
+
# for ensuring that a boolean column accepts nil, but we recommend
|
64
|
+
# using `allow_value` instead, like this:
|
65
|
+
#
|
66
|
+
# it { should allow_value(nil).for(:imported) }
|
67
|
+
#
|
68
|
+
# #### Qualifiers
|
53
69
|
#
|
54
70
|
# ##### with_message
|
55
71
|
#
|
@@ -67,7 +83,7 @@ module Shoulda
|
|
67
83
|
# # RSpec
|
68
84
|
# describe Issue do
|
69
85
|
# it do
|
70
|
-
# should
|
86
|
+
# should validate_inclusion_of(:severity).
|
71
87
|
# in_array(%w(low medium high)).
|
72
88
|
# with_message('Severity must be low, medium, or high')
|
73
89
|
# end
|
@@ -75,7 +91,7 @@ module Shoulda
|
|
75
91
|
#
|
76
92
|
# # Test::Unit
|
77
93
|
# class IssueTest < ActiveSupport::TestCase
|
78
|
-
# should
|
94
|
+
# should validate_inclusion_of(:severity).
|
79
95
|
# in_array(%w(low medium high)).
|
80
96
|
# with_message('Severity must be low, medium, or high')
|
81
97
|
# end
|
@@ -103,7 +119,7 @@ module Shoulda
|
|
103
119
|
# # RSpec
|
104
120
|
# describe Person do
|
105
121
|
# it do
|
106
|
-
# should
|
122
|
+
# should validate_inclusion_of(:age).
|
107
123
|
# in_range(0..65).
|
108
124
|
# with_low_message('You do not receive any benefits')
|
109
125
|
# end
|
@@ -111,7 +127,7 @@ module Shoulda
|
|
111
127
|
#
|
112
128
|
# # Test::Unit
|
113
129
|
# class PersonTest < ActiveSupport::TestCase
|
114
|
-
# should
|
130
|
+
# should validate_inclusion_of(:age).
|
115
131
|
# in_range(0..65).
|
116
132
|
# with_low_message('You do not receive any benefits')
|
117
133
|
# end
|
@@ -139,7 +155,7 @@ module Shoulda
|
|
139
155
|
# # RSpec
|
140
156
|
# describe Person do
|
141
157
|
# it do
|
142
|
-
# should
|
158
|
+
# should validate_inclusion_of(:age).
|
143
159
|
# in_range(0..21).
|
144
160
|
# with_high_message("You're too old for this stuff")
|
145
161
|
# end
|
@@ -147,7 +163,7 @@ module Shoulda
|
|
147
163
|
#
|
148
164
|
# # Test::Unit
|
149
165
|
# class PersonTest < ActiveSupport::TestCase
|
150
|
-
# should
|
166
|
+
# should validate_inclusion_of(:age).
|
151
167
|
# in_range(0..21).
|
152
168
|
# with_high_message("You're too old for this stuff")
|
153
169
|
# end
|
@@ -169,7 +185,7 @@ module Shoulda
|
|
169
185
|
# # RSpec
|
170
186
|
# describe Issue do
|
171
187
|
# it do
|
172
|
-
# should
|
188
|
+
# should validate_inclusion_of(:state).
|
173
189
|
# in_array(%w(open resolved unresolved)).
|
174
190
|
# allow_nil
|
175
191
|
# end
|
@@ -177,7 +193,7 @@ module Shoulda
|
|
177
193
|
#
|
178
194
|
# # Test::Unit
|
179
195
|
# class IssueTest < ActiveSupport::TestCase
|
180
|
-
# should
|
196
|
+
# should validate_inclusion_of(:state).
|
181
197
|
# in_array(%w(open resolved unresolved)).
|
182
198
|
# allow_nil
|
183
199
|
# end
|
@@ -199,7 +215,7 @@ module Shoulda
|
|
199
215
|
# # RSpec
|
200
216
|
# describe Issue do
|
201
217
|
# it do
|
202
|
-
# should
|
218
|
+
# should validate_inclusion_of(:state).
|
203
219
|
# in_array(%w(open resolved unresolved)).
|
204
220
|
# allow_blank
|
205
221
|
# end
|
@@ -207,35 +223,43 @@ module Shoulda
|
|
207
223
|
#
|
208
224
|
# # Test::Unit
|
209
225
|
# class IssueTest < ActiveSupport::TestCase
|
210
|
-
# should
|
226
|
+
# should validate_inclusion_of(:state).
|
211
227
|
# in_array(%w(open resolved unresolved)).
|
212
228
|
# allow_blank
|
213
229
|
# end
|
214
230
|
#
|
215
|
-
# @return [
|
231
|
+
# @return [ValidateInclusionOfMatcher]
|
216
232
|
#
|
233
|
+
def validate_inclusion_of(attr)
|
234
|
+
ValidateInclusionOfMatcher.new(attr)
|
235
|
+
end
|
236
|
+
|
237
|
+
# @deprecated Use {#validate_inclusion_of} instead.
|
238
|
+
# @return [ValidateInclusionOfMatcher]
|
217
239
|
def ensure_inclusion_of(attr)
|
218
|
-
|
240
|
+
Shoulda::Matchers.warn_about_deprecated_method(
|
241
|
+
:ensure_inclusion_of,
|
242
|
+
:validate_inclusion_of
|
243
|
+
)
|
244
|
+
validate_inclusion_of(attr)
|
219
245
|
end
|
220
246
|
|
221
247
|
# @private
|
222
|
-
class
|
248
|
+
class ValidateInclusionOfMatcher < ValidationMatcher
|
223
249
|
ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring'
|
224
250
|
ARBITRARY_OUTSIDE_FIXNUM = 123456789
|
225
251
|
ARBITRARY_OUTSIDE_DECIMAL = BigDecimal.new('0.123456789')
|
226
252
|
BOOLEAN_ALLOWS_BOOLEAN_MESSAGE = <<EOT
|
227
|
-
You are using `
|
228
|
-
boolean values and disallows non-boolean ones.
|
229
|
-
|
230
|
-
|
231
|
-
automatically convert non-boolean values to boolean ones. Hence, you should
|
232
|
-
consider removing this test and the corresponding validation.
|
253
|
+
You are using `validate_inclusion_of` to assert that a boolean column allows
|
254
|
+
boolean values and disallows non-boolean ones. Be aware that it is not possible
|
255
|
+
to fully test this, as boolean columns will automatically convert non-boolean
|
256
|
+
values to boolean ones. Hence, you should consider removing this test.
|
233
257
|
EOT
|
234
258
|
BOOLEAN_ALLOWS_NIL_MESSAGE = <<EOT
|
235
|
-
You are using `
|
259
|
+
You are using `validate_inclusion_of` to assert that a boolean column allows nil.
|
236
260
|
Be aware that it is not possible to fully test this, as anything other than
|
237
261
|
true, false or nil will be converted to false. Hence, you should consider
|
238
|
-
removing this test
|
262
|
+
removing this test.
|
239
263
|
EOT
|
240
264
|
|
241
265
|
def initialize(attribute)
|
@@ -372,7 +396,7 @@ EOT
|
|
372
396
|
def disallows_value_outside_of_array?
|
373
397
|
if attribute_type == :boolean
|
374
398
|
case @array
|
375
|
-
when [true, false]
|
399
|
+
when [false, true], [true, false]
|
376
400
|
Shoulda::Matchers.warn BOOLEAN_ALLOWS_BOOLEAN_MESSAGE
|
377
401
|
return true
|
378
402
|
when [nil]
|
@@ -4,10 +4,10 @@ module Shoulda
|
|
4
4
|
# The `validate_uniqueness_of` matcher tests usage of the
|
5
5
|
# `validates_uniqueness_of` validation. It first checks for an existing
|
6
6
|
# instance of your model in the database, creating one if necessary. It
|
7
|
-
# then takes a new
|
8
|
-
# attribute or attributes you've specified in the
|
9
|
-
# values which are the same as those of the
|
10
|
-
# failing the uniqueness check).
|
7
|
+
# then takes a new instance of that model and asserts that it fails
|
8
|
+
# validation if the attribute or attributes you've specified in the
|
9
|
+
# validation are set to values which are the same as those of the
|
10
|
+
# pre-existing record (thereby failing the uniqueness check).
|
11
11
|
#
|
12
12
|
# class Post < ActiveRecord::Base
|
13
13
|
# validates_uniqueness_of :permalink
|
@@ -29,8 +29,8 @@ module Shoulda
|
|
29
29
|
# before, it will create an instance of your model if one doesn't already
|
30
30
|
# exist. Sometimes this step fails, especially if you have database-level
|
31
31
|
# restrictions on any attributes other than the one which is unique. In
|
32
|
-
# this case, the solution is to
|
33
|
-
# call `validate_uniqueness_of`.
|
32
|
+
# this case, the solution is to populate these attributes with values
|
33
|
+
# before you call `validate_uniqueness_of`.
|
34
34
|
#
|
35
35
|
# For example, say you have the following migration and model:
|
36
36
|
#
|
@@ -62,23 +62,27 @@ module Shoulda
|
|
62
62
|
# ActiveRecord::StatementInvalid:
|
63
63
|
# SQLite3::ConstraintException: posts.content may not be NULL: INSERT INTO "posts" ("title") VALUES (?)
|
64
64
|
#
|
65
|
-
#
|
65
|
+
# This happens because `validate_uniqueness_of` tries to create a new post
|
66
|
+
# but cannot do so because of the `content` attribute: though unrelated to
|
67
|
+
# this test, it nevertheless needs to be filled in. The solution is to
|
68
|
+
# build a custom Post object ahead of time with `content` filled in:
|
66
69
|
#
|
67
70
|
# describe Post do
|
68
|
-
#
|
69
|
-
# Post.
|
70
|
-
# should validate_uniqueness_of(:title)
|
71
|
+
# describe "validations" do
|
72
|
+
# subject { Post.new(content: 'Here is the content') }
|
73
|
+
# it { should validate_uniqueness_of(:title) }
|
71
74
|
# end
|
72
75
|
# end
|
73
76
|
#
|
74
77
|
# Or, if you're using
|
75
78
|
# [FactoryGirl](http://github.com/thoughtbot/factory_girl) and you have a
|
76
|
-
# `post` factory defined which automatically
|
79
|
+
# `post` factory defined which automatically fills in `content`, you can
|
80
|
+
# say:
|
77
81
|
#
|
78
82
|
# describe Post do
|
79
|
-
#
|
80
|
-
# FactoryGirl.
|
81
|
-
# should validate_uniqueness_of(:title)
|
83
|
+
# describe "validations" do
|
84
|
+
# subject { FactoryGirl.build(:post) }
|
85
|
+
# it { should validate_uniqueness_of(:title) }
|
82
86
|
# end
|
83
87
|
# end
|
84
88
|
#
|
@@ -209,6 +213,7 @@ module Shoulda
|
|
209
213
|
end
|
210
214
|
|
211
215
|
def matches?(subject)
|
216
|
+
@original_subject = subject
|
212
217
|
@subject = subject.class.new
|
213
218
|
@expected_message ||= :taken
|
214
219
|
set_scoped_attributes &&
|
@@ -253,16 +258,20 @@ module Shoulda
|
|
253
258
|
value = 'a'
|
254
259
|
end
|
255
260
|
|
256
|
-
@
|
261
|
+
@original_subject.tap do |instance|
|
257
262
|
instance.__send__("#{@attribute}=", value)
|
258
|
-
|
259
|
-
instance.password = 'password'
|
260
|
-
instance.password_confirmation = 'password'
|
261
|
-
end
|
263
|
+
ensure_secure_password_set(instance)
|
262
264
|
instance.save(validate: false)
|
263
265
|
end
|
264
266
|
end
|
265
267
|
|
268
|
+
def ensure_secure_password_set(instance)
|
269
|
+
if has_secure_password?
|
270
|
+
instance.password = "password"
|
271
|
+
instance.password_confirmation = "password"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
266
275
|
def has_secure_password?
|
267
276
|
@subject.class.ancestors.map(&:to_s).include?('ActiveModel::SecurePassword::InstanceMethodsOnActivation')
|
268
277
|
end
|