shoulda-matchers 6.0.0 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
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'