shoulda-matchers 2.8.0.rc1 → 2.8.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.hound.yml +3 -0
- data/.hound_config/ruby.yml +5 -0
- data/.travis.yml +4 -0
- data/.yardopts +1 -1
- data/Appraisals +5 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +7 -5
- data/NEWS.md +24 -0
- data/README.md +9 -0
- data/gemfiles/3.0.gemfile +1 -1
- data/gemfiles/3.0.gemfile.lock +7 -5
- data/gemfiles/3.1.gemfile +1 -1
- data/gemfiles/3.1.gemfile.lock +7 -5
- data/gemfiles/3.1_1.9.2.gemfile +1 -3
- data/gemfiles/3.1_1.9.2.gemfile.lock +7 -12
- data/gemfiles/3.2.gemfile +1 -1
- data/gemfiles/3.2.gemfile.lock +7 -5
- data/gemfiles/3.2_1.9.2.gemfile +1 -3
- data/gemfiles/3.2_1.9.2.gemfile.lock +5 -10
- data/gemfiles/4.0.0.gemfile +1 -1
- data/gemfiles/4.0.0.gemfile.lock +7 -5
- data/gemfiles/4.0.1.gemfile +1 -1
- data/gemfiles/4.0.1.gemfile.lock +7 -5
- data/gemfiles/4.1.gemfile +1 -1
- data/gemfiles/4.1.gemfile.lock +7 -5
- data/gemfiles/4.2.gemfile +5 -3
- data/gemfiles/4.2.gemfile.lock +26 -8
- data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +2 -0
- data/lib/shoulda/matchers/active_model.rb +3 -2
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +44 -32
- data/lib/shoulda/matchers/active_model/helpers.rb +8 -22
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +66 -19
- data/lib/shoulda/matchers/active_model/strict_validator.rb +51 -0
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +14 -13
- data/lib/shoulda/matchers/active_model/validator.rb +113 -0
- data/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb +12 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +19 -1
- data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +23 -2
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +14 -11
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +1 -0
- data/lib/shoulda/matchers/active_record/uniqueness/model.rb +1 -0
- data/lib/shoulda/matchers/active_record/uniqueness/namespace.rb +1 -0
- data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -0
- data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +1 -0
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +22 -15
- data/lib/shoulda/matchers/matcher_context.rb +1 -0
- data/lib/shoulda/matchers/rails_shim.rb +22 -0
- data/lib/shoulda/matchers/util.rb +5 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/update_gem_in_all_appraisals +15 -0
- data/shoulda-matchers.gemspec +1 -1
- data/spec/support/unit/helpers/active_model_helpers.rb +3 -1
- data/spec/support/unit/helpers/active_model_versions.rb +8 -0
- data/spec/support/unit/helpers/active_record_versions.rb +16 -0
- data/spec/support/unit/helpers/rails_versions.rb +4 -4
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +9 -8
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +74 -0
- data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +75 -0
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +24 -0
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +78 -5
- data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +31 -2
- data/spec/unit_spec_helper.rb +2 -0
- metadata +11 -8
- data/lib/shoulda/matchers/active_model/exception_message_finder.rb +0 -58
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +0 -69
- data/spec/unit/shoulda/matchers/active_model/exception_message_finder_spec.rb +0 -111
- data/spec/unit/shoulda/matchers/active_model/validation_message_finder_spec.rb +0 -129
@@ -374,21 +374,7 @@ module Shoulda
|
|
374
374
|
# Assume the scope is a foreign key if the field is nil
|
375
375
|
previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s])
|
376
376
|
|
377
|
-
next_value =
|
378
|
-
if @subject.class.respond_to?(:defined_enums) && @subject.defined_enums[scope.to_s]
|
379
|
-
available_values = @subject.defined_enums[scope.to_s].reject do |key, _|
|
380
|
-
key == previous_value
|
381
|
-
end
|
382
|
-
available_values.keys.last
|
383
|
-
elsif scope.to_s =~ /_type$/ && model_class?(previous_value)
|
384
|
-
Uniqueness::TestModels.create(previous_value).to_s
|
385
|
-
elsif previous_value.respond_to?(:next)
|
386
|
-
previous_value.next
|
387
|
-
elsif previous_value.respond_to?(:to_datetime)
|
388
|
-
previous_value.to_datetime.next
|
389
|
-
else
|
390
|
-
previous_value.to_s.next
|
391
|
-
end
|
377
|
+
next_value = next_value_for(scope, previous_value)
|
392
378
|
|
393
379
|
@subject.__send__("#{scope}=", next_value)
|
394
380
|
|
@@ -418,6 +404,27 @@ module Shoulda
|
|
418
404
|
end
|
419
405
|
end
|
420
406
|
|
407
|
+
def next_value_for(scope, previous_value)
|
408
|
+
if @subject.class.respond_to?(:defined_enums) && @subject.defined_enums[scope.to_s]
|
409
|
+
available_values = available_enum_values_for(scope, previous_value)
|
410
|
+
available_values.keys.last
|
411
|
+
elsif scope.to_s =~ /_type$/ && model_class?(previous_value)
|
412
|
+
Uniqueness::TestModels.create(previous_value).to_s
|
413
|
+
elsif previous_value.respond_to?(:next)
|
414
|
+
previous_value.next
|
415
|
+
elsif previous_value.respond_to?(:to_datetime)
|
416
|
+
previous_value.to_datetime.next
|
417
|
+
else
|
418
|
+
previous_value.to_s.next
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def available_enum_values_for(scope, previous_value)
|
423
|
+
@subject.defined_enums[scope.to_s].reject do |key, _|
|
424
|
+
key == previous_value
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
421
428
|
def class_name
|
422
429
|
@subject.class.name
|
423
430
|
end
|
@@ -65,6 +65,28 @@ module Shoulda
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
def self.generate_validation_message(record, attribute, type, model_name, options)
|
69
|
+
if record && record.errors.respond_to?(:generate_message)
|
70
|
+
record.errors.generate_message(attribute.to_sym, type, options)
|
71
|
+
else
|
72
|
+
simply_generate_validation_message(attribute, type, model_name, options)
|
73
|
+
end
|
74
|
+
rescue RangeError
|
75
|
+
simply_generate_validation_message(attribute, type, model_name, options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.simply_generate_validation_message(attribute, type, model_name, options)
|
79
|
+
default_translation_keys = [
|
80
|
+
:"activerecord.errors.models.#{model_name}.#{type}",
|
81
|
+
:"activerecord.errors.messages.#{type}",
|
82
|
+
:"errors.attributes.#{attribute}.#{type}",
|
83
|
+
:"errors.messages.#{type}"
|
84
|
+
]
|
85
|
+
primary_translation_key = :"activerecord.errors.models.#{model_name}.attributes.#{attribute}.#{type}"
|
86
|
+
translate_options = { default: default_translation_keys }.merge(options)
|
87
|
+
I18n.translate(primary_translation_key, translate_options)
|
88
|
+
end
|
89
|
+
|
68
90
|
def self.active_record_major_version
|
69
91
|
::ActiveRecord::VERSION::MAJOR
|
70
92
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
SUPPORTED_VERSIONS=$(<script/SUPPORTED_VERSIONS)
|
4
|
+
gem="$1"
|
5
|
+
|
6
|
+
update-gem-for-version() {
|
7
|
+
local version="$1"
|
8
|
+
(export RBENV_VERSION=$version; bundle update "$gem" && bundle exec appraisal update "$gem")
|
9
|
+
}
|
10
|
+
|
11
|
+
for version in $SUPPORTED_VERSIONS; do
|
12
|
+
echo
|
13
|
+
echo "*** Updating $gem for $version ***"
|
14
|
+
update-gem-for-version $version
|
15
|
+
done
|
data/shoulda-matchers.gemspec
CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.name = "shoulda-matchers"
|
6
6
|
s.version = Shoulda::Matchers::VERSION.dup
|
7
7
|
s.authors = ["Tammer Saleh", "Joe Ferris", "Ryan McGeary", "Dan Croak",
|
8
|
-
"Matt Jankowski", "Stafford Brunk"]
|
8
|
+
"Matt Jankowski", "Stafford Brunk", "Elliot Winkler"]
|
9
9
|
s.date = Time.now.strftime("%Y-%m-%d")
|
10
10
|
s.email = "support@thoughtbot.com"
|
11
11
|
s.homepage = "http://thoughtbot.com/community/"
|
@@ -7,8 +7,10 @@ module UnitTests
|
|
7
7
|
def custom_validation(options = {}, &block)
|
8
8
|
attribute_name = options.fetch(:attribute_name, :attr)
|
9
9
|
attribute_type = options.fetch(:attribute_type, :integer)
|
10
|
+
column_options = options.fetch(:column_options, {})
|
11
|
+
attribute_options = { type: attribute_type, options: column_options }
|
10
12
|
|
11
|
-
define_model(:example, attribute_name =>
|
13
|
+
define_model(:example, attribute_name => attribute_options) do
|
12
14
|
validate :custom_validation
|
13
15
|
|
14
16
|
define_method(:custom_validation, &block)
|
@@ -5,6 +5,10 @@ module UnitTests
|
|
5
5
|
example_group.extend(self)
|
6
6
|
end
|
7
7
|
|
8
|
+
def active_model_version
|
9
|
+
Tests::Version.new(::ActiveModel::VERSION::STRING)
|
10
|
+
end
|
11
|
+
|
8
12
|
def active_model_3_1?
|
9
13
|
(::ActiveModel::VERSION::MAJOR == 3 && ::ActiveModel::VERSION::MINOR >= 1) || active_model_4_0?
|
10
14
|
end
|
@@ -16,5 +20,9 @@ module UnitTests
|
|
16
20
|
def active_model_4_0?
|
17
21
|
::ActiveModel::VERSION::MAJOR == 4
|
18
22
|
end
|
23
|
+
|
24
|
+
def active_model_supports_strict?
|
25
|
+
active_model_version >= 3.2
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module UnitTests
|
2
|
+
module ActiveRecordVersions
|
3
|
+
def self.configure_example_group(example_group)
|
4
|
+
example_group.include(self)
|
5
|
+
example_group.extend(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
def active_record_version
|
9
|
+
Tests::Version.new(ActiveRecord::VERSION::STRING)
|
10
|
+
end
|
11
|
+
|
12
|
+
def active_record_can_raise_range_error?
|
13
|
+
active_record_version >= 4.2
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -6,19 +6,19 @@ module UnitTests
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def rails_version
|
9
|
-
|
9
|
+
Tests::Version.new(Rails::VERSION::STRING)
|
10
10
|
end
|
11
11
|
|
12
12
|
def rails_3_x?
|
13
|
-
|
13
|
+
rails_version =~ '~> 3.0'
|
14
14
|
end
|
15
15
|
|
16
16
|
def rails_4_x?
|
17
|
-
|
17
|
+
rails_version =~ '~> 4.0'
|
18
18
|
end
|
19
19
|
|
20
20
|
def rails_gte_4_1?
|
21
|
-
|
21
|
+
rails_version >= 4.1
|
22
22
|
end
|
23
23
|
|
24
24
|
def active_record_supports_enum?
|
@@ -20,15 +20,17 @@ module UnitTests
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def failure_message
|
23
|
-
|
23
|
+
lines = ['Expectation should have failed with message:']
|
24
|
+
lines << Shoulda::Matchers::Util.indent(expected, 2)
|
24
25
|
|
25
26
|
if @actual
|
26
|
-
|
27
|
+
lines << 'Actually failed with:'
|
28
|
+
lines << Shoulda::Matchers::Util.indent(@actual, 2)
|
27
29
|
else
|
28
|
-
|
30
|
+
lines << 'However, the expectation did not fail.'
|
29
31
|
end
|
30
32
|
|
31
|
-
|
33
|
+
lines.join("\n")
|
32
34
|
end
|
33
35
|
|
34
36
|
def failure_message_for_should
|
@@ -36,10 +38,9 @@ module UnitTests
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def failure_message_when_negated
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
msg
|
41
|
+
lines = ['Expectation should not have failed with message:']
|
42
|
+
lines << Shoulda::Matchers::Util.indent(expected, 2)
|
43
|
+
lines.join("\n")
|
43
44
|
end
|
44
45
|
|
45
46
|
def failure_message_for_should_not
|
@@ -227,4 +227,78 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
|
|
227
227
|
end
|
228
228
|
end
|
229
229
|
end
|
230
|
+
|
231
|
+
if active_record_can_raise_range_error?
|
232
|
+
context 'when the value is outside of the range of the column' do
|
233
|
+
context 'not qualified with strict' do
|
234
|
+
it 'rejects, failing with the correct message' do
|
235
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
236
|
+
record = define_model(:example, attr: attribute_options).new
|
237
|
+
assertion = -> { expect(record).to allow_value(100000).for(:attr) }
|
238
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
239
|
+
Did not expect errors when attr is set to 100000,
|
240
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
241
|
+
MESSAGE
|
242
|
+
expect(&assertion).to fail_with_message(message)
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'qualified with a message' do
|
246
|
+
it 'ignores any specified message, failing with the correct message' do
|
247
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
248
|
+
record = define_model(:example, attr: attribute_options).new
|
249
|
+
assertion = -> do
|
250
|
+
expect(record).
|
251
|
+
to allow_value(100000).
|
252
|
+
for(:attr).
|
253
|
+
with_message('some message')
|
254
|
+
end
|
255
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
256
|
+
Did not expect errors to include "some message" when attr is set to 100000,
|
257
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
258
|
+
MESSAGE
|
259
|
+
expect(&assertion).to fail_with_message(message)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
if active_model_supports_strict?
|
265
|
+
context 'qualified with strict' do
|
266
|
+
it 'rejects, failing with the correct message' do
|
267
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
268
|
+
record = define_model(:example, attr: attribute_options).new
|
269
|
+
assertion = -> do
|
270
|
+
expect(record).
|
271
|
+
to allow_value(100000).
|
272
|
+
for(:attr).
|
273
|
+
strict
|
274
|
+
end
|
275
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
276
|
+
Did not expect an exception to have been raised when attr is set to 100000,
|
277
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
278
|
+
MESSAGE
|
279
|
+
expect(&assertion).to fail_with_message(message)
|
280
|
+
end
|
281
|
+
|
282
|
+
context 'qualified with a message' do
|
283
|
+
it 'ignores any specified message' do
|
284
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
285
|
+
record = define_model(:example, attr: attribute_options).new
|
286
|
+
assertion = -> do
|
287
|
+
expect(record).
|
288
|
+
to allow_value(100000).
|
289
|
+
for(:attr).
|
290
|
+
with_message('some message').
|
291
|
+
strict
|
292
|
+
end
|
293
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
294
|
+
Did not expect exception to include "some message" when attr is set to 100000,
|
295
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
296
|
+
MESSAGE
|
297
|
+
expect(&assertion).to fail_with_message(message)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
230
304
|
end
|
@@ -79,7 +79,82 @@ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher, type: :model do
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
+
if active_record_can_raise_range_error?
|
83
|
+
context 'when the value is outside of the range of the column' do
|
84
|
+
context 'not qualified with strict' do
|
85
|
+
it 'accepts, failing with the correct message' do
|
86
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
87
|
+
record = define_model(:example, attr: attribute_options).new
|
88
|
+
assertion = -> { expect(record).not_to disallow_value(100000).for(:attr) }
|
89
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
90
|
+
Did not expect errors when attr is set to 100000,
|
91
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
92
|
+
MESSAGE
|
93
|
+
expect(&assertion).to fail_with_message(message)
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'qualified with a message' do
|
97
|
+
it 'ignores any specified message, failing with the correct message' do
|
98
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
99
|
+
record = define_model(:example, attr: attribute_options).new
|
100
|
+
assertion = -> do
|
101
|
+
expect(record).
|
102
|
+
not_to disallow_value(100000).
|
103
|
+
for(:attr).
|
104
|
+
with_message('some message')
|
105
|
+
end
|
106
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
107
|
+
Did not expect errors to include "some message" when attr is set to 100000,
|
108
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
109
|
+
MESSAGE
|
110
|
+
expect(&assertion).to fail_with_message(message)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if active_model_supports_strict?
|
116
|
+
context 'qualified with strict' do
|
117
|
+
it 'accepts, failing with the correct message' do
|
118
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
119
|
+
record = define_model(:example, attr: attribute_options).new
|
120
|
+
assertion = -> do
|
121
|
+
expect(record).
|
122
|
+
not_to disallow_value(100000).
|
123
|
+
for(:attr).
|
124
|
+
strict
|
125
|
+
end
|
126
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
127
|
+
Did not expect an exception to have been raised when attr is set to 100000,
|
128
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
129
|
+
MESSAGE
|
130
|
+
expect(&assertion).to fail_with_message(message)
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'qualified with a message' do
|
134
|
+
it 'ignores any specified message' do
|
135
|
+
attribute_options = { type: :integer, options: { limit: 2 } }
|
136
|
+
record = define_model(:example, attr: attribute_options).new
|
137
|
+
assertion = -> do
|
138
|
+
expect(record).
|
139
|
+
not_to disallow_value(100000).
|
140
|
+
for(:attr).
|
141
|
+
with_message('some message').
|
142
|
+
strict
|
143
|
+
end
|
144
|
+
message = <<-MESSAGE.strip_heredoc.strip
|
145
|
+
Did not expect exception to include "some message" when attr is set to 100000,
|
146
|
+
got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2"
|
147
|
+
MESSAGE
|
148
|
+
expect(&assertion).to fail_with_message(message)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
82
156
|
def matcher(value)
|
83
157
|
described_class.new(value)
|
84
158
|
end
|
159
|
+
alias_method :disallow_value, :matcher
|
85
160
|
end
|