shoulda-matchers 2.6.2 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|