shoulda-matchers 3.1.3 → 4.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.hound/ruby.yml +336 -316
  3. data/.python-version +1 -0
  4. data/.rubocop.yml +3 -1
  5. data/.travis.yml +7 -6
  6. data/Appraisals +76 -44
  7. data/CONTRIBUTING.md +137 -66
  8. data/Gemfile +5 -5
  9. data/Gemfile.lock +30 -35
  10. data/MAINTAINING.md +250 -0
  11. data/MIT-LICENSE +1 -1
  12. data/NEWS.md +176 -4
  13. data/README.md +138 -200
  14. data/Rakefile +7 -0
  15. data/bin/setup +190 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +4 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -6
  18. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -17
  19. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +27 -0
  20. data/gemfiles/4.2.gemfile +21 -20
  21. data/gemfiles/4.2.gemfile.lock +143 -140
  22. data/gemfiles/5.0.gemfile +37 -0
  23. data/gemfiles/5.0.gemfile.lock +238 -0
  24. data/gemfiles/5.1.gemfile +38 -0
  25. data/gemfiles/5.1.gemfile.lock +254 -0
  26. data/gemfiles/5.2.gemfile +40 -0
  27. data/gemfiles/5.2.gemfile.lock +273 -0
  28. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +18 -6
  29. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -1
  30. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
  31. data/lib/shoulda/matchers/action_controller/route_matcher.rb +87 -27
  32. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +1 -0
  33. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +0 -4
  34. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +5 -0
  35. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -0
  36. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +26 -11
  37. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +39 -4
  38. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +116 -47
  39. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +127 -38
  40. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +55 -37
  41. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +30 -1
  42. data/lib/shoulda/matchers/active_model/validation_matcher.rb +11 -4
  43. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +11 -6
  44. data/lib/shoulda/matchers/active_record.rb +3 -0
  45. data/lib/shoulda/matchers/active_record/association_matcher.rb +172 -22
  46. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +1 -1
  47. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +11 -6
  48. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +46 -0
  49. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +51 -0
  50. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +268 -38
  51. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
  52. data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +111 -0
  53. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +207 -79
  54. data/lib/shoulda/matchers/doublespeak/object_double.rb +5 -1
  55. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +100 -21
  56. data/lib/shoulda/matchers/rails_shim.rb +133 -52
  57. data/lib/shoulda/matchers/routing.rb +2 -2
  58. data/lib/shoulda/matchers/util.rb +23 -1
  59. data/lib/shoulda/matchers/util/word_wrap.rb +6 -2
  60. data/lib/shoulda/matchers/version.rb +1 -1
  61. data/script/install_gems_in_all_appraisals +3 -1
  62. data/script/run_all_tests +3 -1
  63. data/script/supported_ruby_versions +7 -0
  64. data/script/update_gem_in_all_appraisals +3 -1
  65. data/script/update_gems_in_all_appraisals +3 -1
  66. data/shoulda-matchers.gemspec +3 -3
  67. data/spec/acceptance/independent_matchers_spec.rb +2 -2
  68. data/spec/acceptance/multiple_libraries_integration_spec.rb +1 -1
  69. data/spec/acceptance/rails_integration_spec.rb +2 -2
  70. data/spec/spec_helper.rb +2 -3
  71. data/spec/support/acceptance/helpers.rb +2 -0
  72. data/spec/support/acceptance/helpers/command_helpers.rb +17 -4
  73. data/spec/support/acceptance/helpers/rails_migration_helpers.rb +21 -0
  74. data/spec/support/acceptance/helpers/step_helpers.rb +1 -1
  75. data/spec/support/tests/current_bundle.rb +3 -9
  76. data/spec/support/tests/filesystem.rb +2 -2
  77. data/spec/support/unit/attribute.rb +0 -2
  78. data/spec/support/unit/capture.rb +9 -3
  79. data/spec/support/unit/helpers/action_pack_versions.rb +22 -0
  80. data/spec/support/unit/helpers/active_model_versions.rb +4 -0
  81. data/spec/support/unit/helpers/active_record_versions.rb +22 -2
  82. data/spec/support/unit/helpers/active_resource_builder.rb +2 -2
  83. data/spec/support/unit/helpers/controller_builder.rb +1 -1
  84. data/spec/support/unit/helpers/message_helpers.rb +19 -0
  85. data/spec/support/unit/helpers/rails_versions.rb +14 -0
  86. data/spec/support/unit/matchers/fail_with_message_matcher.rb +7 -5
  87. data/spec/support/unit/matchers/print_warning_including.rb +21 -13
  88. data/spec/support/unit/model_creation_strategies/active_record.rb +1 -1
  89. data/spec/support/unit/model_creators/active_record.rb +0 -1
  90. data/spec/support/unit/model_creators/basic.rb +7 -2
  91. data/spec/support/unit/rails_application.rb +25 -0
  92. data/spec/support/unit/record_validating_confirmation_builder.rb +5 -2
  93. data/spec/support/unit/validation_matcher_scenario.rb +0 -2
  94. data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +18 -18
  95. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +33 -5
  96. data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +1 -1
  97. data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +80 -78
  98. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +7 -9
  99. data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +28 -4
  100. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +19 -1
  101. data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +27 -4
  102. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +62 -5
  103. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +52 -18
  104. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +51 -4
  105. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +99 -71
  106. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +41 -15
  107. data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +445 -15
  108. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +615 -93
  109. data/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb +169 -0
  110. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +167 -97
  111. data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +2 -4
  112. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +152 -19
  113. data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +258 -94
  114. data/spec/unit_spec_helper.rb +9 -1
  115. data/zeus.json +1 -1
  116. metadata +31 -16
  117. data/gemfiles/4.0.0.gemfile +0 -38
  118. data/gemfiles/4.0.0.gemfile.lock +0 -223
  119. data/gemfiles/4.0.1.gemfile +0 -38
  120. data/gemfiles/4.0.1.gemfile.lock +0 -225
  121. data/gemfiles/4.1.gemfile +0 -38
  122. data/gemfiles/4.1.gemfile.lock +0 -220
  123. data/script/SUPPORTED_VERSIONS +0 -1
@@ -815,16 +815,14 @@ value", but that attribute does not exist.
815
815
  end
816
816
  end
817
817
 
818
- if active_record_supports_enum?
819
- context 'given an ActiveRecord model' do
820
- context 'where the attribute under test is an enum and the given value is a value in that enum' do
821
- it 'accepts' do
822
- model = define_model('Shipment', status: :integer) do
823
- enum status: { pending: 1, shipped: 2, delivered: 3 }
824
- end
825
-
826
- expect(model.new).to allow_value(1).for(:status)
818
+ context 'given an ActiveRecord model' do
819
+ context 'where the attribute under test is an enum and the given value is a value in that enum' do
820
+ it 'accepts' do
821
+ model = define_model('Shipment', status: :integer) do
822
+ enum status: { pending: 1, shipped: 2, delivered: 3 }
827
823
  end
824
+
825
+ expect(model.new).to allow_value(1).for(:status)
828
826
  end
829
827
  end
830
828
  end
@@ -1,7 +1,7 @@
1
1
  require 'unit_spec_helper'
2
2
 
3
3
  describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model do
4
- if active_model_4_0?
4
+ if active_model_supports_absence_validation?
5
5
  def self.available_column_types
6
6
  [
7
7
  :string,
@@ -48,6 +48,27 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
48
48
  end
49
49
  end
50
50
 
51
+ context 'when used in the negative' do
52
+ it 'fails' do
53
+ assertion = lambda do
54
+ expect(validating_absence_of(:attr)).
55
+ not_to validate_absence_of(:attr)
56
+ end
57
+
58
+ message = <<-MESSAGE
59
+ Expected Example not to validate that :attr is empty/falsy, but this
60
+ could not be proved.
61
+ After setting :attr to ‹"an arbitrary value"›, the matcher expected
62
+ the Example to be valid, but it was invalid instead, producing these
63
+ validation errors:
64
+
65
+ * attr: ["must be blank"]
66
+ MESSAGE
67
+
68
+ expect(&assertion).to fail_with_message(message)
69
+ end
70
+ end
71
+
51
72
  def validation_matcher_scenario_args
52
73
  super.deep_merge(model_creator: :active_record)
53
74
  end
@@ -58,7 +79,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
58
79
  record = define_model(:example, attr: :string).new
59
80
 
60
81
  message = <<-MESSAGE
61
- Example did not properly validate that :attr is empty/falsy.
82
+ Expected Example to validate that :attr is empty/falsy, but this could
83
+ not be proved.
62
84
  After setting :attr to ‹"an arbitrary value"›, the matcher expected
63
85
  the Example to be invalid, but it was valid instead.
64
86
  MESSAGE
@@ -97,7 +119,8 @@ Example did not properly validate that :attr is empty/falsy.
97
119
  context 'an ActiveModel class without an absence validation' do
98
120
  it 'rejects with the correct failure message' do
99
121
  message = <<-MESSAGE
100
- Example did not properly validate that :attr is empty/falsy.
122
+ Expected Example to validate that :attr is empty/falsy, but this could
123
+ not be proved.
101
124
  After setting :attr to ‹"an arbitrary value"›, the matcher expected
102
125
  the Example to be invalid, but it was valid instead.
103
126
  MESSAGE
@@ -161,7 +184,8 @@ Example did not properly validate that :attr is empty/falsy.
161
184
  model = having_and_belonging_to_many(:children, absence: false)
162
185
 
163
186
  message = <<-MESSAGE
164
- Parent did not properly validate that :children is empty/falsy.
187
+ Expected Parent to validate that :children is empty/falsy, but this
188
+ could not be proved.
165
189
  After setting :children to ‹[#<Child id: nil>]›, the matcher expected
166
190
  the Parent to be invalid, but it was valid instead.
167
191
  MESSAGE
@@ -21,7 +21,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher, type: :mod
21
21
  attribute_name: :attr,
22
22
  changing_values_with: :always_nil,
23
23
  expected_message: <<-MESSAGE.strip
24
- Example did not properly validate that :attr has been set to "1".
24
+ Expected Example to validate that :attr has been set to "1", but this
25
+ could not be proved.
25
26
  After setting :attr to ‹false› -- which was read back as ‹nil› -- the
26
27
  matcher expected the Example to be invalid, but it was valid instead.
27
28
 
@@ -35,6 +36,23 @@ Example did not properly validate that :attr has been set to "1".
35
36
  },
36
37
  model_creator: :active_model
37
38
  )
39
+
40
+ it 'fails when used in the negative' do
41
+ assertion = lambda do
42
+ expect(record_validating_acceptance).not_to matcher
43
+ end
44
+
45
+ message = <<-MESSAGE
46
+ Expected Example not to validate that :attr has been set to "1", but
47
+ this could not be proved.
48
+ After setting :attr to ‹false›, the matcher expected the Example to be
49
+ valid, but it was invalid instead, producing these validation errors:
50
+
51
+ * attr: ["must be accepted"]
52
+ MESSAGE
53
+
54
+ expect(&assertion).to fail_with_message(message)
55
+ end
38
56
  end
39
57
 
40
58
  context 'a model without an acceptance validation' do
@@ -36,8 +36,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher, type: :m
36
36
  attribute_name: :password,
37
37
  changing_values_with: :next_value,
38
38
  expected_message: <<-MESSAGE.strip
39
- Example did not properly validate that :password_confirmation matches
40
- :password.
39
+ Expected Example to validate that :password_confirmation matches
40
+ :password, but this could not be proved.
41
41
  After setting :password_confirmation to ‹"same value"›, then setting
42
42
  :password to ‹"same value"› -- which was read back as ‹"same valuf"›
43
43
  -- the matcher expected the Example to be valid, but it was invalid
@@ -55,6 +55,29 @@ Example did not properly validate that :password_confirmation matches
55
55
  },
56
56
  model_creator: :active_model
57
57
  )
58
+
59
+ it 'fails when used in the negative' do
60
+ builder = builder_for_record_validating_confirmation(
61
+ model_name: 'Example',
62
+ attribute: :password,
63
+ confirmation_attribute: :password_confirmation
64
+ )
65
+
66
+ assertion = lambda do
67
+ expect(builder.record).
68
+ not_to validate_confirmation_of(builder.attribute_to_confirm)
69
+ end
70
+
71
+ message = <<-MESSAGE
72
+ Expected Example not to validate that :password_confirmation matches
73
+ :password, but this could not be proved.
74
+ After setting :password_confirmation to ‹nil›, then setting :password
75
+ to ‹"any value"›, the matcher expected the Example to be invalid, but
76
+ it was valid instead.
77
+ MESSAGE
78
+
79
+ expect(&assertion).to fail_with_message(message)
80
+ end
58
81
  end
59
82
 
60
83
  context 'when the model does not have a confirmation attribute' do
@@ -108,8 +131,8 @@ The matcher attempted to set :attribute_to_confirm on the Example to
108
131
  end
109
132
 
110
133
  message = <<-MESSAGE
111
- Example did not properly validate that
112
- :attribute_to_confirm_confirmation matches :attribute_to_confirm.
134
+ Expected Example to validate that :attribute_to_confirm_confirmation
135
+ matches :attribute_to_confirm, but this could not be proved.
113
136
  After setting :attribute_to_confirm_confirmation to ‹"some value"›,
114
137
  then setting :attribute_to_confirm to ‹"different value"›, the matcher
115
138
  expected the Example to be invalid, but it was valid instead.
@@ -7,11 +7,26 @@ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :mode
7
7
  to validate_exclusion_of(:attr).in_range(2..5)
8
8
  end
9
9
 
10
- it 'rejects ensuring excluded value' do
10
+ it 'rejects if the given range spills past the top of the range in the validation' do
11
11
  expect(validating_exclusion(in: 2..5)).
12
12
  not_to validate_exclusion_of(:attr).in_range(2..6)
13
13
  end
14
14
 
15
+ it 'rejects if the given range falls short of the top of the range in the validation' do
16
+ expect(validating_exclusion(in: 2..5)).
17
+ not_to validate_exclusion_of(:attr).in_range(2..4)
18
+ end
19
+
20
+ it 'rejects if the given range spills past the bottom of the range in the validation' do
21
+ expect(validating_exclusion(in: 2..5)).
22
+ not_to validate_exclusion_of(:attr).in_range(1..5)
23
+ end
24
+
25
+ it 'rejects if the given range falls short of the bottom of the range in the validation' do
26
+ expect(validating_exclusion(in: 2..5)).
27
+ not_to validate_exclusion_of(:attr).in_range(3..5)
28
+ end
29
+
15
30
  it 'does not override the default message with a blank' do
16
31
  expect(validating_exclusion(in: 2..5)).
17
32
  to validate_exclusion_of(:attr).in_range(2..5).with_message(nil)
@@ -25,8 +40,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :mode
25
40
  attribute_name: :attr,
26
41
  changing_values_with: :next_value,
27
42
  expected_message: <<-MESSAGE.strip
28
- Example did not properly validate that :attr lies outside the range ‹2›
29
- to ‹5›.
43
+ Expected Example to validate that :attr lies outside the range ‹2› to
44
+ ‹5›, but this could not be proved.
30
45
  After setting :attr to ‹1› -- which was read back as ‹2› -- the
31
46
  matcher expected the Example to be valid, but it was invalid instead,
32
47
  producing these validation errors:
@@ -51,6 +66,22 @@ to ‹5›.
51
66
  matcher.in_range(2..5)
52
67
  end
53
68
  end
69
+
70
+ it 'fails when used in the negative' do
71
+ assertion = lambda do
72
+ expect(validating_exclusion(in: 2..5)).
73
+ not_to validate_exclusion_of(:attr).in_range(2..5)
74
+ end
75
+
76
+ message = <<-MESSAGE
77
+ Expected Example not to validate that :attr lies outside the range ‹2›
78
+ to ‹5›, but this could not be proved.
79
+ After setting :attr to ‹6›, the matcher expected the Example to be
80
+ invalid, but it was valid instead.
81
+ MESSAGE
82
+
83
+ expect(&assertion).to fail_with_message(message)
84
+ end
54
85
  end
55
86
 
56
87
  context 'an attribute which must be excluded from a range with excluded end' do
@@ -70,6 +101,14 @@ to ‹5›.
70
101
  expect(validating_exclusion(in: 2..4, message: 'not good')).
71
102
  to validate_exclusion_of(:attr).in_range(2..4).with_message(/not good/)
72
103
  end
104
+
105
+ it 'accepts ensuring the correct range with an interpolated variable in the message' do
106
+ matcher = validating_exclusion(in: 2..4, message: '%{value} is not good')
107
+ expect(matcher).
108
+ to validate_exclusion_of(:attr).
109
+ in_range(2..4).
110
+ with_message(/^[234] is not good$/)
111
+ end
73
112
  end
74
113
 
75
114
  context 'an attribute with custom range validations' do
@@ -153,8 +192,8 @@ to ‹5›.
153
192
  attribute_name: :attr,
154
193
  changing_values_with: :next_value,
155
194
  expected_message: <<-MESSAGE.strip
156
- Example did not properly validate that :attr is neither ‹"one"› nor
157
- ‹"two"›.
195
+ Expected Example to validate that :attr is neither ‹"one"› nor ‹"two"›,
196
+ but this could not be proved.
158
197
  After setting :attr to ‹"one"› -- which was read back as ‹"onf"› --
159
198
  the matcher expected the Example to be invalid, but it was valid
160
199
  instead.
@@ -178,6 +217,24 @@ Example did not properly validate that :attr is neither ‹"one"› nor
178
217
  end
179
218
  end
180
219
 
220
+ it 'fails when used in the negative' do
221
+ assertion = lambda do
222
+ expect(validating_exclusion(in: %w(one two))).
223
+ not_to validate_exclusion_of(:attr).in_array(%w(one two))
224
+ end
225
+
226
+ message = <<-MESSAGE
227
+ Expected Example not to validate that :attr is neither ‹"one"› nor
228
+ ‹"two"›, but this could not be proved.
229
+ After setting :attr to ‹"two"›, the matcher expected the Example to be
230
+ valid, but it was invalid instead, producing these validation errors:
231
+
232
+ * attr: ["is reserved"]
233
+ MESSAGE
234
+
235
+ expect(&assertion).to fail_with_message(message)
236
+ end
237
+
181
238
  def define_model_validating_exclusion(options)
182
239
  options = options.dup
183
240
  column_type = options.delete(:column_type) { :string }
@@ -25,7 +25,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
25
25
  it_behaves_like 'it supports in_array',
26
26
  possible_values: (1..5).to_a,
27
27
  zero: 0,
28
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_FIXNUM
28
+ reserved_outside_value: described_class::ARBITRARY_OUTSIDE_INTEGER
29
29
 
30
30
  it_behaves_like 'it supports in_range',
31
31
  possible_values: 1..5,
@@ -82,7 +82,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
82
82
  it_behaves_like 'it supports in_array',
83
83
  possible_values: [1.0, 2.0, 3.0, 4.0, 5.0],
84
84
  zero: 0.0,
85
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_FIXNUM
85
+ reserved_outside_value: described_class::ARBITRARY_OUTSIDE_INTEGER
86
86
 
87
87
  it_behaves_like 'it supports in_range',
88
88
  possible_values: 1.0..5.0,
@@ -192,20 +192,19 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
192
192
  end
193
193
 
194
194
  context 'against a time attribute' do
195
- now = Time.now
195
+ default_time = Time.zone.local(2000, 1, 1)
196
196
 
197
- define_method(:now) { now }
197
+ define_method(:default_time) { default_time }
198
198
 
199
199
  it_behaves_like 'it supports in_array',
200
- possible_values: (1..5).map { |n| now + n },
201
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_TIME
200
+ possible_values: (1..3).map { |hour| default_time.change(hour: hour) }
202
201
 
203
202
  it_behaves_like 'it supports in_range',
204
- possible_values: (now .. now + 5)
203
+ possible_values: (default_time.change(hour: 1) .. default_time.change(hour: 3))
205
204
 
206
205
  define_method :build_object do |options = {}, &block|
207
206
  build_object_with_generic_attribute(
208
- options.merge(column_type: :time, value: now),
207
+ options.merge(column_type: :time, value: default_time),
209
208
  &block
210
209
  )
211
210
  end
@@ -215,7 +214,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
215
214
  end
216
215
 
217
216
  def validation_matcher_scenario_args
218
- super.deep_merge(column_type: :time, default_value: now)
217
+ super.deep_merge(column_type: :time, default_value: default_time)
219
218
  end
220
219
  end
221
220
 
@@ -368,6 +367,17 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
368
367
  end
369
368
  end
370
369
 
370
+ it 'matches when validation uses given message that has an interpolated variable' do
371
+ builder = build_object_allowing(
372
+ valid_values,
373
+ validation_options: { message: '%{value} is not included' },
374
+ )
375
+
376
+ expect_to_match_on_values(builder, valid_values) do |matcher|
377
+ matcher.with_message(/ is not included\Z/)
378
+ end
379
+ end
380
+
371
381
  it 'does not match when validation uses the default message instead of given message' do
372
382
  builder = build_object_allowing(valid_values)
373
383
 
@@ -434,13 +444,25 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
434
444
  shared_examples_for 'it supports in_array' do |args|
435
445
  possible_values = args.fetch(:possible_values)
436
446
  zero = args[:zero]
437
- reserved_outside_value = args.fetch(:reserved_outside_value)
447
+ reserved_outside_value = args[:reserved_outside_value]
438
448
 
439
449
  define_method(:valid_values) { args.fetch(:possible_values) }
440
450
 
441
- it 'does not match a record with no validations' do
442
- builder = build_object
443
- expect_not_to_match_on_values(builder, possible_values)
451
+ context 'when the record has no validations' do
452
+ it 'passes when used in the negative' do
453
+ builder = build_object
454
+ expect_not_to_match_on_values(builder, possible_values)
455
+ end
456
+
457
+ it 'fails when used in the positive with an appropriate failure message' do
458
+ builder = build_object
459
+
460
+ assertion = lambda do
461
+ expect_to_match_on_values(builder, possible_values)
462
+ end
463
+
464
+ expect(&assertion).to fail
465
+ end
444
466
  end
445
467
 
446
468
  it 'matches given the same array of valid values' do
@@ -466,12 +488,24 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
466
488
  expect_not_to_match_on_values(builder, add_outside_value_to(possible_values))
467
489
  end
468
490
 
469
- it 'raises an error when valid and given value is our test outside value' do
470
- error_class = Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray
471
- builder = build_object_allowing([reserved_outside_value])
491
+ if reserved_outside_value
492
+ it 'raises an error when valid and given value is our test outside value' do
493
+ error_class = Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray
494
+ builder = build_object_allowing([reserved_outside_value])
495
+
496
+ expect { expect_to_match_on_values(builder, [reserved_outside_value]) }.
497
+ to raise_error(error_class)
498
+ end
499
+ end
500
+
501
+ it 'fails when used in the negative' do
502
+ builder = build_object_allowing(possible_values)
503
+
504
+ assertion = lambda do
505
+ expect_not_to_match_on_values(builder, possible_values)
506
+ end
472
507
 
473
- expect { expect_to_match_on_values(builder, [reserved_outside_value]) }.
474
- to raise_error(error_class)
508
+ expect(&assertion).to fail
475
509
  end
476
510
 
477
511
  it_behaves_like 'it supports allow_nil', valid_values: possible_values
@@ -33,8 +33,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateLengthOfMatcher, type: :model d
33
33
  attribute_name: :attr,
34
34
  changing_values_with: :add_character,
35
35
  expected_message: <<-MESSAGE.strip
36
- Example did not properly validate that the length of :attr is at least
37
- 4.
36
+ Expected Example to validate that the length of :attr is at least 4, but
37
+ this could not be proved.
38
38
  After setting :attr to ‹"xxx"› -- which was read back as ‹"xxxa"› --
39
39
  the matcher expected the Example to be invalid, but it was valid
40
40
  instead.
@@ -56,6 +56,22 @@ Example did not properly validate that the length of :attr is at least
56
56
  matcher.is_at_least(4)
57
57
  end
58
58
  end
59
+
60
+ it 'fails when used in the negative' do
61
+ assertion = lambda do
62
+ expect(validating_length(minimum: 4)).
63
+ not_to validate_length_of(:attr).is_at_least(4)
64
+ end
65
+
66
+ message = <<-MESSAGE
67
+ Expected Example not to validate that the length of :attr is at least 4,
68
+ but this could not be proved.
69
+ After setting :attr to ‹"xxxx"›, the matcher expected the Example to
70
+ be invalid, but it was valid instead.
71
+ MESSAGE
72
+
73
+ expect(&assertion).to fail_with_message(message)
74
+ end
59
75
  end
60
76
 
61
77
  context 'an attribute with a minimum length validation of 0' do
@@ -97,7 +113,8 @@ Example did not properly validate that the length of :attr is at least
97
113
  attribute_name: :attr,
98
114
  changing_values_with: :remove_character,
99
115
  expected_message: <<-MESSAGE.strip
100
- Example did not properly validate that the length of :attr is at most 4.
116
+ Expected Example to validate that the length of :attr is at most 4, but
117
+ this could not be proved.
101
118
  After setting :attr to ‹"xxxxx"› -- which was read back as ‹"xxxx"› --
102
119
  the matcher expected the Example to be invalid, but it was valid
103
120
  instead.
@@ -153,7 +170,8 @@ Example did not properly validate that the length of :attr is at most 4.
153
170
  attribute_name: :attr,
154
171
  changing_values_with: :add_character,
155
172
  expected_message: <<-MESSAGE.strip
156
- Example did not properly validate that the length of :attr is 4.
173
+ Expected Example to validate that the length of :attr is 4, but this
174
+ could not be proved.
157
175
  After setting :attr to ‹"xxx"› -- which was read back as ‹"xxxa"› --
158
176
  the matcher expected the Example to be invalid, but it was valid
159
177
  instead.
@@ -264,6 +282,35 @@ Example did not properly validate that the length of :attr is 4.
264
282
  end
265
283
  end
266
284
 
285
+ context 'qualified with allow_nil' do
286
+ context 'and validating with allow_nil' do
287
+ it 'accepts' do
288
+ expect(validating_length(minimum: 1, allow_nil: true)).
289
+ to validate_length_of(:attr).is_at_least(1).allow_nil
290
+ end
291
+ end
292
+
293
+ context 'and not validating with allow_nil' do
294
+ it 'rejects' do
295
+ assertion = lambda do
296
+ expect(validating_length(minimum: 1)).
297
+ to validate_length_of(:attr).is_at_least(1).allow_nil
298
+ end
299
+
300
+ message = <<-MESSAGE
301
+ Expected Example to validate that the length of :attr is at least 1, but
302
+ this could not be proved.
303
+ After setting :attr to ‹nil›, the matcher expected the Example to be
304
+ valid, but it was invalid instead, producing these validation errors:
305
+
306
+ * attr: ["is too short (minimum is 1 character)"]
307
+ MESSAGE
308
+
309
+ expect(&assertion).to fail_with_message(message)
310
+ end
311
+ end
312
+ end
313
+
267
314
  def define_model_validating_length(options = {})
268
315
  options = options.dup
269
316
  attribute_name = options.delete(:attribute_name) { :attr }