mcmire-shoulda-matchers 2.5.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.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +32 -0
  4. data/.yardopts +7 -0
  5. data/Appraisals +45 -0
  6. data/CONTRIBUTING.md +41 -0
  7. data/Gemfile +31 -0
  8. data/Gemfile.lock +166 -0
  9. data/MIT-LICENSE +22 -0
  10. data/NEWS.md +299 -0
  11. data/README.md +163 -0
  12. data/Rakefile +116 -0
  13. data/doc_config/gh-pages/index.html.erb +9 -0
  14. data/doc_config/yard/setup.rb +22 -0
  15. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
  18. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
  19. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
  20. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
  21. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
  22. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
  23. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +300 -0
  24. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
  25. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
  26. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
  27. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
  28. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
  29. data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
  30. data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
  31. data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
  32. data/doc_config/yard/templates/default/layout/html/setup.rb +8 -0
  33. data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
  34. data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
  35. data/features/rails_integration.feature +113 -0
  36. data/features/step_definitions/rails_steps.rb +162 -0
  37. data/features/support/env.rb +5 -0
  38. data/gemfiles/3.0.gemfile +24 -0
  39. data/gemfiles/3.0.gemfile.lock +150 -0
  40. data/gemfiles/3.1.gemfile +27 -0
  41. data/gemfiles/3.1.gemfile.lock +173 -0
  42. data/gemfiles/3.2.gemfile +27 -0
  43. data/gemfiles/3.2.gemfile.lock +171 -0
  44. data/gemfiles/4.0.0.gemfile +28 -0
  45. data/gemfiles/4.0.0.gemfile.lock +172 -0
  46. data/gemfiles/4.0.1.gemfile +28 -0
  47. data/gemfiles/4.0.1.gemfile.lock +172 -0
  48. data/lib/shoulda-matchers.rb +1 -0
  49. data/lib/shoulda/matchers.rb +11 -0
  50. data/lib/shoulda/matchers/action_controller.rb +17 -0
  51. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +64 -0
  52. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +97 -0
  53. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +81 -0
  54. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +117 -0
  55. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +114 -0
  56. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +154 -0
  57. data/lib/shoulda/matchers/action_controller/route_matcher.rb +116 -0
  58. data/lib/shoulda/matchers/action_controller/route_params.rb +48 -0
  59. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +164 -0
  60. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +296 -0
  61. data/lib/shoulda/matchers/active_model.rb +30 -0
  62. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +167 -0
  63. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +314 -0
  64. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +46 -0
  65. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +160 -0
  66. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +417 -0
  67. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +337 -0
  68. data/lib/shoulda/matchers/active_model/errors.rb +10 -0
  69. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +58 -0
  70. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +92 -0
  71. data/lib/shoulda/matchers/active_model/helpers.rb +46 -0
  72. data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  73. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +75 -0
  74. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +27 -0
  75. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +41 -0
  76. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +27 -0
  77. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +26 -0
  78. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +112 -0
  79. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +77 -0
  80. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +121 -0
  81. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +380 -0
  82. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +89 -0
  83. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +372 -0
  84. data/lib/shoulda/matchers/active_model/validation_matcher.rb +97 -0
  85. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +69 -0
  86. data/lib/shoulda/matchers/active_record.rb +22 -0
  87. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +204 -0
  88. data/lib/shoulda/matchers/active_record/association_matcher.rb +901 -0
  89. data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  90. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +41 -0
  91. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +41 -0
  92. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +81 -0
  93. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +65 -0
  94. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +94 -0
  95. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
  96. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +41 -0
  97. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +63 -0
  98. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +261 -0
  99. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +149 -0
  100. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +72 -0
  101. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +181 -0
  102. data/lib/shoulda/matchers/assertion_error.rb +19 -0
  103. data/lib/shoulda/matchers/error.rb +6 -0
  104. data/lib/shoulda/matchers/integrations/rspec.rb +20 -0
  105. data/lib/shoulda/matchers/integrations/test_unit.rb +30 -0
  106. data/lib/shoulda/matchers/rails_shim.rb +50 -0
  107. data/lib/shoulda/matchers/version.rb +6 -0
  108. data/lib/shoulda/matchers/warn.rb +8 -0
  109. data/shoulda-matchers.gemspec +23 -0
  110. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
  111. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
  112. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
  113. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +63 -0
  114. data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +63 -0
  115. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
  116. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +70 -0
  117. data/spec/shoulda/matchers/action_controller/route_params_spec.rb +30 -0
  118. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
  119. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
  120. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
  121. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +170 -0
  122. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +81 -0
  123. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +95 -0
  124. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +320 -0
  125. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +166 -0
  126. data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +111 -0
  127. data/spec/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +20 -0
  128. data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
  129. data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +169 -0
  130. data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
  131. data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
  132. data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +57 -0
  133. data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +139 -0
  134. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
  135. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +47 -0
  136. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +331 -0
  137. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +180 -0
  138. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +398 -0
  139. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +127 -0
  140. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +107 -0
  141. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +860 -0
  142. data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +247 -0
  143. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
  144. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
  145. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
  146. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
  147. data/spec/spec_helper.rb +26 -0
  148. data/spec/support/active_model_versions.rb +13 -0
  149. data/spec/support/active_resource_builder.rb +29 -0
  150. data/spec/support/activemodel_helpers.rb +19 -0
  151. data/spec/support/capture_helpers.rb +19 -0
  152. data/spec/support/class_builder.rb +42 -0
  153. data/spec/support/controller_builder.rb +74 -0
  154. data/spec/support/fail_with_message_including_matcher.rb +33 -0
  155. data/spec/support/fail_with_message_matcher.rb +32 -0
  156. data/spec/support/i18n_faker.rb +10 -0
  157. data/spec/support/mailer_builder.rb +10 -0
  158. data/spec/support/model_builder.rb +81 -0
  159. data/spec/support/rails_versions.rb +18 -0
  160. data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
  161. data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
  162. data/spec/support/test_application.rb +120 -0
  163. data/yard.watchr +5 -0
  164. metadata +281 -0
@@ -0,0 +1,320 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::EnsureInclusionOfMatcher do
4
+ context 'with no validations' do
5
+ it 'rejects an array which does not have a validator defined' do
6
+ expect(define_model(:example, attr: :string).new).
7
+ not_to ensure_inclusion_of(:attr).in_array(%w(Yes No))
8
+ end
9
+ end
10
+
11
+ context 'with an integer column' do
12
+ it 'can verify a zero in the array' do
13
+ model = define_model(:example, attr: :integer) do
14
+ validates_inclusion_of :attr, in: [0, 1, 2]
15
+ end.new
16
+
17
+ expect(model).to ensure_inclusion_of(:attr).in_array([0,1,2])
18
+ end
19
+ end
20
+
21
+ context 'with an decimal column' do
22
+ it 'can verify decimal values' do
23
+ model = define_model(:example, attr: :decimal) do
24
+ validates_inclusion_of :attr, in: [0.0, 0.1]
25
+ end.new
26
+
27
+ expect(model).to ensure_inclusion_of(:attr).in_array([0.0, 0.1])
28
+ end
29
+ end
30
+
31
+ context 'with true/false values' do
32
+ it 'can verify outside values to ensure the negative case' do
33
+ expect(define_model(:example, attr: :string).new).
34
+ not_to ensure_inclusion_of(:attr).in_array([true, false])
35
+ end
36
+ end
37
+
38
+ context 'where we cannot determine a value outside the array' do
39
+ it 'raises a custom exception' do
40
+ model = define_model(:example, attr: :string).new
41
+
42
+ arbitrary_string = described_class::ARBITRARY_OUTSIDE_STRING
43
+ expect { expect(model).to ensure_inclusion_of(:attr).in_array([arbitrary_string]) }.to raise_error Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray
44
+ end
45
+ end
46
+
47
+ context 'an attribute which must be included in a range' do
48
+ it 'accepts ensuring the correct range' do
49
+ expect(validating_inclusion(in: 2..5)).
50
+ to ensure_inclusion_of(:attr).in_range(2..5)
51
+ end
52
+
53
+ it 'rejects ensuring a lower minimum value' do
54
+ expect(validating_inclusion(in: 2..5)).
55
+ not_to ensure_inclusion_of(:attr).in_range(1..5)
56
+ end
57
+
58
+ it 'rejects ensuring a higher minimum value' do
59
+ expect(validating_inclusion(in: 2..5)).
60
+ not_to ensure_inclusion_of(:attr).in_range(3..5)
61
+ end
62
+
63
+ it 'rejects ensuring a lower maximum value' do
64
+ expect(validating_inclusion(in: 2..5)).
65
+ not_to ensure_inclusion_of(:attr).in_range(2..4)
66
+ end
67
+
68
+ it 'rejects ensuring a higher maximum value' do
69
+ expect(validating_inclusion(in: 2..5)).
70
+ not_to ensure_inclusion_of(:attr).in_range(2..6)
71
+ end
72
+
73
+ it 'does not override the default message with a blank' do
74
+ expect(validating_inclusion(in: 2..5)).
75
+ to ensure_inclusion_of(:attr).in_range(2..5).with_message(nil)
76
+ end
77
+ end
78
+
79
+ context 'an attribute which must be included in a range with excluded end' do
80
+ it 'accepts ensuring the correct range' do
81
+ expect(validating_inclusion(in: 2...5)).
82
+ to ensure_inclusion_of(:attr).in_range(2...5)
83
+ end
84
+
85
+ it 'rejects ensuring a lower maximum value' do
86
+ expect(validating_inclusion(in: 2...5)).
87
+ not_to ensure_inclusion_of(:attr).in_range(2...4)
88
+ end
89
+ end
90
+
91
+ context 'an attribute with a custom ranged value validation' do
92
+ it 'accepts ensuring the correct range' do
93
+ expect(validating_inclusion(in: 2..4, message: 'not good')).
94
+ to ensure_inclusion_of(:attr).in_range(2..4).with_message(/not good/)
95
+ end
96
+ end
97
+
98
+ context 'an attribute with custom range validations' do
99
+ it 'accepts ensuring the correct range and messages' do
100
+ model = custom_validation do
101
+ if attr < 2
102
+ errors.add(:attr, 'too low')
103
+ elsif attr > 5
104
+ errors.add(:attr, 'too high')
105
+ end
106
+ end
107
+
108
+ expect(model).to ensure_inclusion_of(:attr).in_range(2..5).
109
+ with_low_message(/low/).with_high_message(/high/)
110
+
111
+ model = custom_validation do
112
+ if attr < 2
113
+ errors.add(:attr, 'too low')
114
+ elsif attr > 4
115
+ errors.add(:attr, 'too high')
116
+ end
117
+ end
118
+
119
+ expect(model).to ensure_inclusion_of(:attr).in_range(2...5).
120
+ with_low_message(/low/).with_high_message(/high/)
121
+ end
122
+ end
123
+
124
+ context 'an attribute which must be included in an array' do
125
+ it 'accepts with correct array' do
126
+ expect(validating_inclusion(in: %w(one two))).
127
+ to ensure_inclusion_of(:attr).in_array(%w(one two))
128
+ end
129
+
130
+ it 'rejects when only part of array matches' do
131
+ expect(validating_inclusion(in: %w(one two))).
132
+ not_to ensure_inclusion_of(:attr).in_array(%w(one wrong_value))
133
+ end
134
+
135
+ it 'rejects when array does not match at all' do
136
+ expect(validating_inclusion(in: %w(one two))).
137
+ not_to ensure_inclusion_of(:attr).in_array(%w(cat dog))
138
+ end
139
+
140
+ it 'has correct description' do
141
+ expect(ensure_inclusion_of(:attr).in_array([true, "dog"]).description).
142
+ to eq 'ensure inclusion of attr in [true, "dog"]'
143
+ end
144
+
145
+ it 'rejects allow_blank' do
146
+ expect(validating_inclusion(in: %w(one two))).
147
+ not_to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank(true)
148
+ end
149
+
150
+ it 'accepts allow_blank(false)' do
151
+ expect(validating_inclusion(in: %w(one two))).
152
+ to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank(false)
153
+ end
154
+
155
+ it 'rejects allow_nil' do
156
+ expect(validating_inclusion(in: %w(one two))).
157
+ not_to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil(true)
158
+ end
159
+
160
+ it 'accepts allow_nil(false)' do
161
+ expect(validating_inclusion(in: %w(one two))).
162
+ to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil(false)
163
+ end
164
+ end
165
+
166
+ context 'with allowed blank and allowed nil' do
167
+ it 'accepts allow_blank' do
168
+ expect(validating_inclusion(in: %w(one two), allow_blank: true)).
169
+ to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank
170
+ end
171
+
172
+ it 'rejects allow_blank(false)' do
173
+ expect(validating_inclusion(in: %w(one two), allow_blank: true)).
174
+ not_to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_blank(false)
175
+ end
176
+
177
+ it 'accepts allow_nil' do
178
+ expect(validating_inclusion(in: %w(one two), allow_nil: true)).
179
+ to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil
180
+ end
181
+
182
+ it 'rejects allow_nil' do
183
+ expect(validating_inclusion(in: %w(one two), allow_nil: true)).
184
+ not_to ensure_inclusion_of(:attr).in_array(%w(one two)).allow_nil(false)
185
+ end
186
+ end
187
+
188
+ context 'an attribute allowing some blank values but not others' do
189
+ it 'rejects allow_blank' do
190
+ expect(validating_inclusion(in: ['one', 'two', ''])).
191
+ not_to ensure_inclusion_of(:attr).in_array(['one', 'two', '']).allow_blank(true)
192
+ end
193
+ end
194
+
195
+ if active_model_3_2?
196
+ context 'a strict attribute which must be included in a range' do
197
+ it 'accepts ensuring the correct range' do
198
+ expect(validating_inclusion(in: 2..5, strict: true)).
199
+ to ensure_inclusion_of(:attr).in_range(2..5).strict
200
+ end
201
+
202
+ it 'rejects ensuring another range' do
203
+ expect(validating_inclusion(in: 2..5, strict: true)).
204
+ not_to ensure_inclusion_of(:attr).in_range(2..6).strict
205
+ end
206
+ end
207
+ end
208
+
209
+ context 'against a boolean attribute' do
210
+ context 'which is nullable' do
211
+ context 'when ensuring inclusion of true' do
212
+ it "doesn't raise an error" do
213
+ record = validating_inclusion_of_boolean_in(:attr, [true], null: true)
214
+ expect(record).to ensure_inclusion_of(:attr).in_array([true])
215
+ end
216
+ end
217
+
218
+ context 'when ensuring inclusion of false' do
219
+ it "doesn't raise an error" do
220
+ record = validating_inclusion_of_boolean_in(:attr, [false], null: true)
221
+ expect(record).to ensure_inclusion_of(:attr).in_array([false])
222
+ end
223
+ end
224
+
225
+ context 'when ensuring inclusion of true and false' do
226
+ it "doesn't raise an error" do
227
+ record = validating_inclusion_of_boolean_in(:attr, [true, false], null: true)
228
+ capture(:stderr) do
229
+ expect(record).to ensure_inclusion_of(:attr).in_array([true, false])
230
+ end
231
+ end
232
+
233
+ it 'prints a warning' do
234
+ record = validating_inclusion_of_boolean_in(:attr, [true, false], null: true)
235
+ stderr = capture(:stderr) do
236
+ expect(record).to ensure_inclusion_of(:attr).in_array([true, false])
237
+ end
238
+ expect(stderr.gsub(/\n+/, ' ')).
239
+ to include('You are using `ensure_inclusion_of` to assert that a boolean column allows boolean values and disallows non-boolean ones')
240
+ end
241
+ end
242
+
243
+ context 'when ensuring inclusion of nil' do
244
+ it "doesn't raise an error" do
245
+ record = validating_inclusion_of_boolean_in(:attr, [nil], null: true)
246
+ capture(:stderr) do
247
+ expect(record).to ensure_inclusion_of(:attr).in_array([nil])
248
+ end
249
+ end
250
+
251
+ it 'prints a warning' do
252
+ record = validating_inclusion_of_boolean_in(:attr, [nil], null: true)
253
+ stderr = capture(:stderr) do
254
+ expect(record).to ensure_inclusion_of(:attr).in_array([nil])
255
+ end
256
+ expect(stderr.gsub(/\n+/, ' ')).
257
+ to include('You are using `ensure_inclusion_of` to assert that a boolean column allows nil')
258
+ end
259
+ end
260
+ end
261
+
262
+ context 'which is non-nullable' do
263
+ context 'when ensuring inclusion of true' do
264
+ it "doesn't raise an error" do
265
+ record = validating_inclusion_of_boolean_in(:attr, [true], null: false)
266
+ expect(record).to ensure_inclusion_of(:attr).in_array([true])
267
+ end
268
+ end
269
+
270
+ context 'when ensuring inclusion of false' do
271
+ it "doesn't raise an error" do
272
+ record = validating_inclusion_of_boolean_in(:attr, [false], null: false)
273
+ expect(record).to ensure_inclusion_of(:attr).in_array([false])
274
+ end
275
+ end
276
+
277
+ context 'when ensuring inclusion of true and false' do
278
+ it "doesn't raise an error" do
279
+ record = validating_inclusion_of_boolean_in(:attr, [true, false], null: false)
280
+ capture(:stderr) do
281
+ expect(record).to ensure_inclusion_of(:attr).in_array([true, false])
282
+ end
283
+ end
284
+
285
+ it 'prints a warning' do
286
+ record = validating_inclusion_of_boolean_in(:attr, [true, false], null: false)
287
+ stderr = capture(:stderr) do
288
+ expect(record).to ensure_inclusion_of(:attr).in_array([true, false])
289
+ end
290
+ expect(stderr.gsub(/\n+/, ' ')).
291
+ to include('You are using `ensure_inclusion_of` to assert that a boolean column allows boolean values and disallows non-boolean ones')
292
+ end
293
+ end
294
+
295
+ context 'when ensuring inclusion of nil' do
296
+ it 'raises a specific error' do
297
+ record = validating_inclusion_of_boolean_in(:attr, [nil], null: false)
298
+ error_class = Shoulda::Matchers::ActiveModel::NonNullableBooleanError
299
+ expect {
300
+ expect(record).to ensure_inclusion_of(:attr).in_array([nil])
301
+ }.to raise_error(error_class)
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+ def validating_inclusion(options)
308
+ define_model(:example, attr: :string) do
309
+ validates_inclusion_of :attr, options
310
+ end.new
311
+ end
312
+
313
+ def validating_inclusion_of_boolean_in(attribute, values, options = {})
314
+ null = options.fetch(:null, true)
315
+ column_options = { type: :boolean, options: { null: null } }
316
+ define_model(:example, attribute => column_options) do
317
+ validates_inclusion_of attribute, in: values
318
+ end.new
319
+ end
320
+ end
@@ -0,0 +1,166 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::EnsureLengthOfMatcher do
4
+ context 'an attribute with a non-zero minimum length validation' do
5
+ it 'accepts ensuring the correct minimum length' do
6
+ expect(validating_length(minimum: 4)).
7
+ to ensure_length_of(:attr).is_at_least(4)
8
+ end
9
+
10
+ it 'rejects ensuring a lower minimum length with any message' do
11
+ expect(validating_length(minimum: 4)).
12
+ not_to ensure_length_of(:attr).is_at_least(3).with_short_message(/.*/)
13
+ end
14
+
15
+ it 'rejects ensuring a higher minimum length with any message' do
16
+ expect(validating_length(minimum: 4)).
17
+ not_to ensure_length_of(:attr).is_at_least(5).with_short_message(/.*/)
18
+ end
19
+
20
+ it 'does not override the default message with a blank' do
21
+ expect(validating_length(minimum: 4)).
22
+ to ensure_length_of(:attr).is_at_least(4).with_short_message(nil)
23
+ end
24
+ end
25
+
26
+ context 'an attribute with a minimum length validation of 0' do
27
+ it 'accepts ensuring the correct minimum length' do
28
+ expect(validating_length(minimum: 0)).
29
+ to ensure_length_of(:attr).is_at_least(0)
30
+ end
31
+ end
32
+
33
+ context 'an attribute with a maximum length' do
34
+ it 'accepts ensuring the correct maximum length' do
35
+ expect(validating_length(maximum: 4)).
36
+ to ensure_length_of(:attr).is_at_most(4)
37
+ end
38
+
39
+ it 'rejects ensuring a lower maximum length with any message' do
40
+ expect(validating_length(maximum: 4)).
41
+ not_to ensure_length_of(:attr).is_at_most(3).with_long_message(/.*/)
42
+ end
43
+
44
+ it 'rejects ensuring a higher maximum length with any message' do
45
+ expect(validating_length(maximum: 4)).
46
+ not_to ensure_length_of(:attr).is_at_most(5).with_long_message(/.*/)
47
+ end
48
+
49
+ it 'does not override the default message with a blank' do
50
+ expect(validating_length(maximum: 4)).
51
+ to ensure_length_of(:attr).is_at_most(4).with_long_message(nil)
52
+ end
53
+ end
54
+
55
+ context 'an attribute with a required exact length' do
56
+ it 'accepts ensuring the correct length' do
57
+ expect(validating_length(is: 4)).to ensure_length_of(:attr).is_equal_to(4)
58
+ end
59
+
60
+ it 'rejects ensuring a lower maximum length with any message' do
61
+ expect(validating_length(is: 4)).
62
+ not_to ensure_length_of(:attr).is_equal_to(3).with_message(/.*/)
63
+ end
64
+
65
+ it 'rejects ensuring a higher maximum length with any message' do
66
+ expect(validating_length(is: 4)).
67
+ not_to ensure_length_of(:attr).is_equal_to(5).with_message(/.*/)
68
+ end
69
+
70
+ it 'does not override the default message with a blank' do
71
+ expect(validating_length(is: 4)).
72
+ to ensure_length_of(:attr).is_equal_to(4).with_message(nil)
73
+ end
74
+ end
75
+
76
+ context 'an attribute with a required exact length and another validation' do
77
+ it 'accepts ensuring the correct length' do
78
+ model = define_model(:example, attr: :string) do
79
+ validates_length_of :attr, is: 4
80
+ validates_numericality_of :attr
81
+ end.new
82
+
83
+ expect(model).to ensure_length_of(:attr).is_equal_to(4)
84
+ end
85
+ end
86
+
87
+ context 'an attribute with a custom minimum length validation' do
88
+ it 'accepts ensuring the correct minimum length' do
89
+ expect(validating_length(minimum: 4, too_short: 'foobar')).
90
+ to ensure_length_of(:attr).is_at_least(4).with_short_message(/foo/)
91
+ end
92
+ end
93
+
94
+ context 'an attribute with a custom maximum length validation' do
95
+ it 'accepts ensuring the correct minimum length' do
96
+ expect(validating_length(maximum: 4, too_long: 'foobar')).
97
+ to ensure_length_of(:attr).is_at_most(4).with_long_message(/foo/)
98
+ end
99
+ end
100
+
101
+ context 'an attribute with a custom equal validation' do
102
+ it 'accepts ensuring the correct exact length' do
103
+ expect(validating_length(is: 4, message: 'foobar')).
104
+ to ensure_length_of(:attr).is_equal_to(4).with_message(/foo/)
105
+ end
106
+ end
107
+
108
+ context 'an attribute without a length validation' do
109
+ it 'rejects ensuring a minimum length' do
110
+ expect(define_model(:example, attr: :string).new).
111
+ not_to ensure_length_of(:attr).is_at_least(1)
112
+ end
113
+ end
114
+
115
+ context 'using translations' do
116
+ after { I18n.backend.reload! }
117
+
118
+ context "a too_long translation containing %{attribute}, %{model}" do
119
+ before do
120
+ stub_translation(
121
+ "activerecord.errors.messages.too_long",
122
+ "The %{attribute} of your %{model} is too long (maximum is %{count} characters)")
123
+ end
124
+
125
+ it "does not raise an exception" do
126
+ expect {
127
+ expect(validating_length(maximum: 4)).to ensure_length_of(:attr).is_at_most(4)
128
+ }.to_not raise_exception
129
+ end
130
+ end
131
+
132
+ context "a too_short translation containing %{attribute}, %{model}" do
133
+ before do
134
+ stub_translation(
135
+ "activerecord.errors.messages.too_short",
136
+ "The %{attribute} of your %{model} is too short (minimum is %{count} characters)")
137
+ end
138
+
139
+ it "does not raise an exception" do
140
+ expect {
141
+ expect(validating_length(minimum: 4)).to ensure_length_of(:attr).is_at_least(4)
142
+ }.to_not raise_exception
143
+ end
144
+ end
145
+
146
+ context "a wrong_length translation containing %{attribute}, %{model}" do
147
+ before do
148
+ stub_translation(
149
+ "activerecord.errors.messages.wrong_length",
150
+ "The %{attribute} of your %{model} is the wrong length (should be %{count} characters)")
151
+ end
152
+
153
+ it "does not raise an exception" do
154
+ expect {
155
+ expect(validating_length(is: 4)).to ensure_length_of(:attr).is_equal_to(4)
156
+ }.to_not raise_exception
157
+ end
158
+ end
159
+ end
160
+
161
+ def validating_length(options = {})
162
+ define_model(:example, attr: :string) do
163
+ validates_length_of :attr, options
164
+ end.new
165
+ end
166
+ end