shoulda-matchers 6.0.0 → 6.2.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -9
  3. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -8
  4. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +13 -15
  5. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +37 -1
  6. data/lib/shoulda/matchers/active_model/comparison_matcher.rb +1 -6
  7. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +7 -0
  8. data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +0 -5
  9. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +0 -6
  10. data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +11 -13
  11. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +20 -8
  12. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +9 -11
  13. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +6 -7
  14. data/lib/shoulda/matchers/active_record/association_matcher.rb +543 -15
  15. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +9 -1
  16. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -0
  17. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +4 -0
  18. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +23 -19
  19. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +27 -23
  20. data/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
  21. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +10 -10
  22. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -1
  23. data/lib/shoulda/matchers/active_record/normalize_matcher.rb +1 -1
  24. data/lib/shoulda/matchers/active_record/uniqueness/model.rb +1 -1
  25. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +82 -70
  26. data/lib/shoulda/matchers/active_record.rb +1 -0
  27. data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -6
  28. data/lib/shoulda/matchers/doublespeak/world.rb +2 -6
  29. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +12 -14
  30. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +7 -5
  31. data/lib/shoulda/matchers/integrations/libraries/routing.rb +5 -3
  32. data/lib/shoulda/matchers/util.rb +17 -19
  33. data/lib/shoulda/matchers/version.rb +1 -1
  34. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '00039d1c47436bb88b431784a2b956713382face294b6bbe5c7599378ce03a55'
4
- data.tar.gz: 27640030d1ada19757e5da4d9c10465f422234f8dde9242a54bcb002585c71d5
3
+ metadata.gz: d549ac8f3629ad37bc56d0d09daf37416ec23d78374a8ed6a630ea23e5c9e487
4
+ data.tar.gz: f09bc94b6be181564cdde56729c2055192a4725adee4ba8b6b7f8e84429fe9a0
5
5
  SHA512:
6
- metadata.gz: 51aff6ac4ab386f8df5dec81dfca4f197604d206263b29b711146820dda54ef5f9a9aa723aa6ce14084364eccdcbfbb8c3b1c38f2a4cdcbfc5d3ae8e8c965806
7
- data.tar.gz: 476b055e38257cc8d6841a96779a012ef68cd01239c26c15b170c251a4f7655bab6344a7c163361e9ef283142994bc04ed69f8c6bbccf1bae3acfafc5fd62176
6
+ metadata.gz: 1f3ba08a6d15ad56cb583c0a8289e180854f5d89020b3182b2d6140289800d71bca467f187c9a4718ba26078cc2562f6377d77b00a0e84f2e683079d62ef60d3
7
+ data.tar.gz: 45d0141c79d9642439c9c03ffcd8e41d1aee993eafaea11fc72812456ead1dcf17d1698e9eb7f311c40945c54c77fc4e573a820ffa115fc344e9b0049ed69479
data/README.md CHANGED
@@ -55,7 +55,7 @@ Start by including `shoulda-matchers` in your Gemfile:
55
55
 
56
56
  ```ruby
57
57
  group :test do
58
- gem 'shoulda-matchers', '~> 5.0'
58
+ gem 'shoulda-matchers', '~> 6.0'
59
59
  end
60
60
  ```
61
61
 
@@ -117,7 +117,7 @@ Otherwise, add `shoulda-matchers` to your Gemfile:
117
117
 
118
118
  ```ruby
119
119
  group :test do
120
- gem 'shoulda-matchers', '~> 5.0'
120
+ gem 'shoulda-matchers', '~> 6.0'
121
121
  end
122
122
  ```
123
123
 
@@ -385,8 +385,10 @@ about any of them, make sure to [consult the documentation][rubydocs]!
385
385
  tests your `belongs_to` associations.
386
386
  * **[define_enum_for](lib/shoulda/matchers/active_record/define_enum_for_matcher.rb)**
387
387
  tests usage of the `enum` macro.
388
- * **[have_and_belong_to_many](lib/shoulda/matchers/active_record/association_matcher.rb#L827)**
388
+ * **[have_and_belong_to_many](lib/shoulda/matchers/active_record/association_matcher.rb)**
389
389
  tests your `has_and_belongs_to_many` associations.
390
+ * **[have_delegated_type](lib/shoulda/matchers/active_record/association_matcher.rb#L687)**
391
+ tests usage of the `delegated_type` macro.
390
392
  * **[have_db_column](lib/shoulda/matchers/active_record/have_db_column_matcher.rb)**
391
393
  tests that the table that backs your model has a specific column.
392
394
  * **[have_db_index](lib/shoulda/matchers/active_record/have_db_index_matcher.rb)**
@@ -411,6 +413,8 @@ about any of them, make sure to [consult the documentation][rubydocs]!
411
413
  tests usage of `validates_uniqueness_of`.
412
414
  * **[normalize](lib/shoulda/matchers/active_record/normalize_matcher.rb)** tests
413
415
  usage of the `normalize` macro
416
+ * **[encrypt](lib/shoulda/matchers/active_record/encrypt_matcher.rb)**
417
+ tests usage of the `encrypts` macro.
414
418
 
415
419
  ### ActionController matchers
416
420
 
@@ -513,16 +517,21 @@ redistributed under the terms specified in the [LICENSE](LICENSE) file.
513
517
 
514
518
  [thoughtbot-website]: https://thoughtbot.com
515
519
 
520
+ <!-- START /templates/footer.md -->
516
521
  ## About thoughtbot
517
522
 
518
- ![thoughtbot][thoughtbot-logo]
519
-
520
- [thoughtbot-logo]: https://thoughtbot.com/brand_assets/93:44.svg
523
+ ![thoughtbot](https://thoughtbot.com/thoughtbot-logo-for-readmes.svg)
521
524
 
525
+ This repo is maintained and funded by thoughtbot, inc.
522
526
  The names and logos for thoughtbot are trademarks of thoughtbot, inc.
523
527
 
524
- We are passionate about open source software. See [our other
525
- projects][community]. We are [available for hire][hire].
528
+ We love open source software!
529
+ See [our other projects][community].
530
+
531
+ We are [available for hire][hire].
526
532
 
527
533
  [community]: https://thoughtbot.com/community?utm_source=github
528
- [hire]: https://thoughtbot.com?utm_source=github
534
+ [hire]: https://thoughtbot.com/hire-us?utm_source=github
535
+
536
+
537
+ <!-- END /templates/footer.md -->
@@ -276,16 +276,14 @@ module Shoulda
276
276
  :context, :subparameter_name, :parameters_double_registry
277
277
 
278
278
  def expectation
279
- message = 'restrict parameters '
279
+ String.new('restrict parameters ').tap do |message|
280
+ if subparameter_name
281
+ message << "on #{subparameter_name.inspect} "
282
+ end
280
283
 
281
- if subparameter_name
282
- message << "on #{subparameter_name.inspect} "
284
+ message << 'to '\
285
+ "#{format_parameter_names(expected_permitted_parameter_names)}"
283
286
  end
284
-
285
- message << 'to '\
286
- "#{format_parameter_names(expected_permitted_parameter_names)}"
287
-
288
- message
289
287
  end
290
288
 
291
289
  def reality
@@ -83,25 +83,23 @@ module Shoulda
83
83
  end
84
84
 
85
85
  def expectation_description
86
- string = 'set'
87
-
88
- string <<
89
- if key_set?
90
- " #{store.name}[#{key.inspect}]"
91
- else
92
- " any key in #{store.name}"
93
- end
94
-
95
- if expected_value_set?
86
+ String.new('set').tap do |string|
96
87
  string <<
97
- if expected_value.is_a?(Regexp)
98
- " to a value matching #{expected_value.inspect}"
88
+ if key_set?
89
+ " #{store.name}[#{key.inspect}]"
99
90
  else
100
- " to #{expected_value.inspect}"
91
+ " any key in #{store.name}"
101
92
  end
102
- end
103
93
 
104
- string
94
+ if expected_value_set?
95
+ string <<
96
+ if expected_value.is_a?(Regexp)
97
+ " to a value matching #{expected_value.inspect}"
98
+ else
99
+ " to #{expected_value.inspect}"
100
+ end
101
+ end
102
+ end
105
103
  end
106
104
  end
107
105
  end
@@ -169,6 +169,36 @@ module Shoulda
169
169
  # on(:create)
170
170
  # end
171
171
  #
172
+ # ##### against
173
+ #
174
+ # Use `against` if the validation is on an attribute
175
+ # other than the attribute being validated:
176
+ #
177
+ # class UserProfile
178
+ # include ActiveModel::Model
179
+ # attr_accessor :website_url
180
+ #
181
+ # alias_attribute :url, :website_url
182
+ #
183
+ # validates_format_of :url, with: URI.regexp
184
+ # end
185
+ #
186
+ # # RSpec
187
+ # RSpec.describe UserProfile, type: :model do
188
+ # it do
189
+ # should allow_value('https://foo.com').
190
+ # for(:website_url).
191
+ # against(:url)
192
+ # end
193
+ # end
194
+ #
195
+ # # Minitest (Shoulda)
196
+ # class UserProfileTest < ActiveSupport::TestCase
197
+ # should allow_value('https://foo.com').
198
+ # for(:website_url).
199
+ # against(:url)
200
+ # end
201
+ #
172
202
  # ##### with_message
173
203
  #
174
204
  # Use `with_message` if you are using a custom validation message.
@@ -349,6 +379,12 @@ module Shoulda
349
379
  self
350
380
  end
351
381
 
382
+ def against(attribute)
383
+ @attribute_to_check_message_against = attribute if attribute.present?
384
+
385
+ self
386
+ end
387
+
352
388
  def with_message(message, given_options = {})
353
389
  if message.present?
354
390
  @expects_custom_validation_message = true
@@ -550,7 +586,7 @@ module Shoulda
550
586
  end
551
587
 
552
588
  def default_failure_message_preface
553
- ''.tap do |preface|
589
+ String.new.tap do |preface|
554
590
  if descriptions_for_preset_values.any?
555
591
  preface << 'After setting '
556
592
  preface << descriptions_for_preset_values.to_sentence
@@ -50,7 +50,7 @@ module Shoulda
50
50
  description = ''
51
51
 
52
52
  if expects_strict?
53
- description << ' strictly'
53
+ description = ' strictly'
54
54
  end
55
55
 
56
56
  description +
@@ -78,11 +78,6 @@ module Shoulda
78
78
  comparison_submatchers.matches?(subject)
79
79
  end
80
80
 
81
- def does_not_match?(subject)
82
- @subject = subject
83
- comparison_submatchers.does_not_match?(subject)
84
- end
85
-
86
81
  def comparison_description
87
82
  "#{comparison_expectation} #{@value}"
88
83
  end
@@ -47,6 +47,8 @@ module Shoulda
47
47
  did_not_authenticate_correct_password: 'expected %{subject} to'\
48
48
  ' authenticate the correct %{attribute}',
49
49
  method_not_found: 'expected %{subject} to respond to %{methods}',
50
+ should_not_have_secure_password: 'expected %{subject} to'\
51
+ ' not %{description}!',
50
52
  }.freeze
51
53
 
52
54
  def initialize(attribute)
@@ -69,6 +71,11 @@ module Shoulda
69
71
  failure.nil?
70
72
  end
71
73
 
74
+ def failure_message_when_negated
75
+ MESSAGES[:should_not_have_secure_password] %
76
+ { subject: @subject.class, description: description }
77
+ end
78
+
72
79
  protected
73
80
 
74
81
  attr_reader :subject
@@ -13,11 +13,6 @@ module Shoulda
13
13
  failing_submatchers.empty?
14
14
  end
15
15
 
16
- def does_not_match?(subject)
17
- @subject = subject
18
- non_failing_submatchers.empty?
19
- end
20
-
21
16
  def failure_message
22
17
  failing_submatcher.failure_message
23
18
  end
@@ -143,12 +143,6 @@ module Shoulda
143
143
  @subject.class.reflect_on_association(@attribute)
144
144
  end
145
145
 
146
- def array_column?
147
- @subject.class.respond_to?(:columns_hash) &&
148
- @subject.class.columns_hash[@attribute.to_s].respond_to?(:array) &&
149
- @subject.class.columns_hash[@attribute.to_s].array
150
- end
151
-
152
146
  def enum_column?
153
147
  @subject.class.respond_to?(:defined_enums) &&
154
148
  @subject.class.defined_enums.key?(@attribute.to_s)
@@ -13,12 +13,12 @@ module Shoulda
13
13
  #
14
14
  # # RSpec
15
15
  # RSpec.describe Person, type: :model do
16
- # it { should validate_comparison_of(:gpa).greater_than(10) }
16
+ # it { should validate_comparison_of(:gpa).is_greater_than(10) }
17
17
  # end
18
18
  #
19
19
  # # Minitest (Shoulda)
20
20
  # class PersonTest < ActiveSupport::TestCase
21
- # should validate_comparison_of(:gpa).greater_than(10)
21
+ # should validate_comparison_of(:gpa).is_greater_than(10)
22
22
  # end
23
23
  #
24
24
  # #### Qualifiers
@@ -39,14 +39,14 @@ module Shoulda
39
39
  # RSpec.describe Person, type: :model do
40
40
  # it do
41
41
  # should validate_comparison_of(:number_of_dependents).
42
- # greater_than(0).
42
+ # is_greater_than(0).
43
43
  # on(:create)
44
44
  # end
45
45
  # end
46
46
  #
47
47
  # # Minitest (Shoulda)
48
48
  # class PersonTest < ActiveSupport::TestCase
49
- # should validate_comparison_of(:number_of_dependents).greater_than(0).on(:create)
49
+ # should validate_comparison_of(:number_of_dependents).is_greater_than(0).on(:create)
50
50
  # end
51
51
  #
52
52
  # ##### is_less_than
@@ -353,16 +353,14 @@ module Shoulda
353
353
  end
354
354
 
355
355
  def simple_description
356
- description = ''
357
-
358
- description << "validate that :#{attribute} looks like "
359
- description << Shoulda::Matchers::Util.a_or_an(allowed_type_name)
356
+ String.new.tap do |description|
357
+ description << "validate that :#{attribute} looks like "
358
+ description << Shoulda::Matchers::Util.a_or_an(allowed_type_name)
360
359
 
361
- if comparison_descriptions.present?
362
- description << " #{comparison_descriptions}"
360
+ if comparison_descriptions.present?
361
+ description << " #{comparison_descriptions}"
362
+ end
363
363
  end
364
-
365
- description
366
364
  end
367
365
 
368
366
  def failure_message
@@ -465,7 +463,7 @@ module Shoulda
465
463
  def first_submatcher_that_fails_to_not_match
466
464
  @_first_submatcher_that_fails_to_not_match ||=
467
465
  @submatchers.detect do |submatcher|
468
- !submatcher.does_not_match?(subject)
466
+ submatcher.matches?(subject)
469
467
  end
470
468
  end
471
469
 
@@ -309,8 +309,8 @@ EOT
309
309
 
310
310
  def in_range(range)
311
311
  @range = range
312
- @minimum = range.first
313
- @maximum = range.max
312
+ @minimum = minimum_range_value
313
+ @maximum = maximum_range_value
314
314
  self
315
315
  end
316
316
 
@@ -400,6 +400,18 @@ EOT
400
400
 
401
401
  private
402
402
 
403
+ def minimum_range_value
404
+ @range.begin
405
+ end
406
+
407
+ def maximum_range_value
408
+ if @range.exclude_end?
409
+ @range.end ? (@range.end - 1) : nil
410
+ else
411
+ @range.end
412
+ end
413
+ end
414
+
403
415
  def matches_for_range?
404
416
  disallows_lower_value &&
405
417
  allows_minimum_value &&
@@ -441,27 +453,27 @@ EOT
441
453
  end
442
454
 
443
455
  def allows_minimum_value
444
- allows_value_of(@minimum, @low_message)
456
+ @minimum.nil? || allows_value_of(@minimum, @low_message)
445
457
  end
446
458
 
447
459
  def disallows_minimum_value
448
- disallows_value_of(@minimum, @low_message)
460
+ @minimum.nil? || disallows_value_of(@minimum, @low_message)
449
461
  end
450
462
 
451
463
  def allows_maximum_value
452
- allows_value_of(@maximum, @high_message)
464
+ @maximum.nil? || allows_value_of(@maximum, @high_message)
453
465
  end
454
466
 
455
467
  def disallows_maximum_value
456
- disallows_value_of(@maximum, @high_message)
468
+ @maximum.nil? || disallows_value_of(@maximum, @high_message)
457
469
  end
458
470
 
459
471
  def allows_higher_value
460
- allows_value_of(@maximum + 1, @high_message)
472
+ @maximum.nil? || allows_value_of(@maximum + 1, @high_message)
461
473
  end
462
474
 
463
475
  def disallows_higher_value
464
- disallows_value_of(@maximum + 1, @high_message)
476
+ @maximum.nil? || disallows_value_of(@maximum + 1, @high_message)
465
477
  end
466
478
 
467
479
  def allows_all_values_in_array?
@@ -453,20 +453,18 @@ module Shoulda
453
453
  end
454
454
 
455
455
  def simple_description
456
- description = ''
456
+ String.new.tap do |description|
457
+ description << "validate that :#{attribute} looks like "
458
+ description << Shoulda::Matchers::Util.a_or_an(full_allowed_type)
457
459
 
458
- description << "validate that :#{attribute} looks like "
459
- description << Shoulda::Matchers::Util.a_or_an(full_allowed_type)
460
-
461
- if range_description.present?
462
- description << " #{range_description}"
463
- end
460
+ if range_description.present?
461
+ description << " #{range_description}"
462
+ end
464
463
 
465
- if comparison_descriptions.present?
466
- description << " #{comparison_descriptions}"
464
+ if comparison_descriptions.present?
465
+ description << " #{comparison_descriptions}"
466
+ end
467
467
  end
468
-
469
- description
470
468
  end
471
469
 
472
470
  def failure_message
@@ -42,13 +42,12 @@ module Shoulda
42
42
  description_clauses = []
43
43
 
44
44
  if matcher.try(:expects_strict?)
45
- description_clauses << 'raising a validation exception'
46
-
47
- if matcher.try(:expects_custom_validation_message?)
48
- description_clauses.last << ' with a custom message'
49
- end
50
-
51
- description_clauses.last << ' on failure'
45
+ description_clauses <<
46
+ if matcher.try(:expects_custom_validation_message?)
47
+ 'raising a validation exception with a custom message on failure'
48
+ else
49
+ 'raising a validation exception on failure'
50
+ end
52
51
  elsif matcher.try(:expects_custom_validation_message?)
53
52
  description_clauses <<
54
53
  'producing a custom validation error on failure'