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.
- checksums.yaml +4 -4
- data/.hound/ruby.yml +336 -316
- data/.python-version +1 -0
- data/.rubocop.yml +3 -1
- data/.travis.yml +7 -6
- data/Appraisals +76 -44
- data/CONTRIBUTING.md +137 -66
- data/Gemfile +5 -5
- data/Gemfile.lock +30 -35
- data/MAINTAINING.md +250 -0
- data/MIT-LICENSE +1 -1
- data/NEWS.md +176 -4
- data/README.md +138 -200
- data/Rakefile +7 -0
- data/bin/setup +190 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +4 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -6
- data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -17
- data/doc_config/yard/templates/default/fulldoc/html/setup.rb +27 -0
- data/gemfiles/4.2.gemfile +21 -20
- data/gemfiles/4.2.gemfile.lock +143 -140
- data/gemfiles/5.0.gemfile +37 -0
- data/gemfiles/5.0.gemfile.lock +238 -0
- data/gemfiles/5.1.gemfile +38 -0
- data/gemfiles/5.1.gemfile.lock +254 -0
- data/gemfiles/5.2.gemfile +40 -0
- data/gemfiles/5.2.gemfile.lock +273 -0
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +18 -6
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -1
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +87 -27
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +1 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +0 -4
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +5 -0
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -0
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +26 -11
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +39 -4
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +116 -47
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +127 -38
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +55 -37
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +30 -1
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +11 -4
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +11 -6
- data/lib/shoulda/matchers/active_record.rb +3 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +172 -22
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +11 -6
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +46 -0
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +51 -0
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +268 -38
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +111 -0
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +207 -79
- data/lib/shoulda/matchers/doublespeak/object_double.rb +5 -1
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +100 -21
- data/lib/shoulda/matchers/rails_shim.rb +133 -52
- data/lib/shoulda/matchers/routing.rb +2 -2
- data/lib/shoulda/matchers/util.rb +23 -1
- data/lib/shoulda/matchers/util/word_wrap.rb +6 -2
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/install_gems_in_all_appraisals +3 -1
- data/script/run_all_tests +3 -1
- data/script/supported_ruby_versions +7 -0
- data/script/update_gem_in_all_appraisals +3 -1
- data/script/update_gems_in_all_appraisals +3 -1
- data/shoulda-matchers.gemspec +3 -3
- data/spec/acceptance/independent_matchers_spec.rb +2 -2
- data/spec/acceptance/multiple_libraries_integration_spec.rb +1 -1
- data/spec/acceptance/rails_integration_spec.rb +2 -2
- data/spec/spec_helper.rb +2 -3
- data/spec/support/acceptance/helpers.rb +2 -0
- data/spec/support/acceptance/helpers/command_helpers.rb +17 -4
- data/spec/support/acceptance/helpers/rails_migration_helpers.rb +21 -0
- data/spec/support/acceptance/helpers/step_helpers.rb +1 -1
- data/spec/support/tests/current_bundle.rb +3 -9
- data/spec/support/tests/filesystem.rb +2 -2
- data/spec/support/unit/attribute.rb +0 -2
- data/spec/support/unit/capture.rb +9 -3
- data/spec/support/unit/helpers/action_pack_versions.rb +22 -0
- data/spec/support/unit/helpers/active_model_versions.rb +4 -0
- data/spec/support/unit/helpers/active_record_versions.rb +22 -2
- data/spec/support/unit/helpers/active_resource_builder.rb +2 -2
- data/spec/support/unit/helpers/controller_builder.rb +1 -1
- data/spec/support/unit/helpers/message_helpers.rb +19 -0
- data/spec/support/unit/helpers/rails_versions.rb +14 -0
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +7 -5
- data/spec/support/unit/matchers/print_warning_including.rb +21 -13
- data/spec/support/unit/model_creation_strategies/active_record.rb +1 -1
- data/spec/support/unit/model_creators/active_record.rb +0 -1
- data/spec/support/unit/model_creators/basic.rb +7 -2
- data/spec/support/unit/rails_application.rb +25 -0
- data/spec/support/unit/record_validating_confirmation_builder.rb +5 -2
- data/spec/support/unit/validation_matcher_scenario.rb +0 -2
- data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +18 -18
- data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +33 -5
- data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +1 -1
- data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +80 -78
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +7 -9
- data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +28 -4
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +19 -1
- data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +27 -4
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +62 -5
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +52 -18
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +51 -4
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +99 -71
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +41 -15
- data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +445 -15
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +615 -93
- data/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb +169 -0
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +167 -97
- data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +2 -4
- data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +152 -19
- data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +258 -94
- data/spec/unit_spec_helper.rb +9 -1
- data/zeus.json +1 -1
- metadata +31 -16
- data/gemfiles/4.0.0.gemfile +0 -38
- data/gemfiles/4.0.0.gemfile.lock +0 -223
- data/gemfiles/4.0.1.gemfile +0 -38
- data/gemfiles/4.0.1.gemfile.lock +0 -225
- data/gemfiles/4.1.gemfile +0 -38
- data/gemfiles/4.1.gemfile.lock +0 -220
- data/script/SUPPORTED_VERSIONS +0 -1
@@ -10,7 +10,7 @@ module Shoulda
|
|
10
10
|
# pre-existing record (thereby failing the uniqueness check).
|
11
11
|
#
|
12
12
|
# class Post < ActiveRecord::Base
|
13
|
-
#
|
13
|
+
# validates :permalink, uniqueness: true
|
14
14
|
# end
|
15
15
|
#
|
16
16
|
# # RSpec
|
@@ -80,19 +80,19 @@ module Shoulda
|
|
80
80
|
#
|
81
81
|
# RSpec.describe Post, type: :model do
|
82
82
|
# describe "validations" do
|
83
|
-
# subject { Post.
|
83
|
+
# subject { Post.create(content: "Here is the content") }
|
84
84
|
# it { should validate_uniqueness_of(:title) }
|
85
85
|
# end
|
86
86
|
# end
|
87
87
|
#
|
88
88
|
# Or, if you're using
|
89
|
-
# [
|
89
|
+
# [FactoryBot](https://github.com/thoughtbot/factory_bot) and you have a
|
90
90
|
# `post` factory defined which automatically fills in `content`, you can
|
91
91
|
# say:
|
92
92
|
#
|
93
93
|
# RSpec.describe Post, type: :model do
|
94
94
|
# describe "validations" do
|
95
|
-
# subject {
|
95
|
+
# subject { FactoryBot.create(:post) }
|
96
96
|
# it { should validate_uniqueness_of(:title) }
|
97
97
|
# end
|
98
98
|
# end
|
@@ -102,7 +102,7 @@ module Shoulda
|
|
102
102
|
# Use `on` if your validation applies only under a certain context.
|
103
103
|
#
|
104
104
|
# class Post < ActiveRecord::Base
|
105
|
-
#
|
105
|
+
# validates :title, uniqueness: true, on: :create
|
106
106
|
# end
|
107
107
|
#
|
108
108
|
# # RSpec
|
@@ -120,7 +120,7 @@ module Shoulda
|
|
120
120
|
# Use `with_message` if you are using a custom validation message.
|
121
121
|
#
|
122
122
|
# class Post < ActiveRecord::Base
|
123
|
-
#
|
123
|
+
# validates :title, uniqueness: true, message: 'Please choose another title'
|
124
124
|
# end
|
125
125
|
#
|
126
126
|
# # RSpec
|
@@ -144,7 +144,7 @@ module Shoulda
|
|
144
144
|
# unique, but the scoped attributes are not unique either.
|
145
145
|
#
|
146
146
|
# class Post < ActiveRecord::Base
|
147
|
-
#
|
147
|
+
# validates :slug, uniqueness: true, scope: :journal_id
|
148
148
|
# end
|
149
149
|
#
|
150
150
|
# # RSpec
|
@@ -165,7 +165,7 @@ module Shoulda
|
|
165
165
|
# attributes in the pre-existing record.
|
166
166
|
#
|
167
167
|
# class Post < ActiveRecord::Base
|
168
|
-
#
|
168
|
+
# validates :key, uniqueness: { case_sensitive: false }
|
169
169
|
# end
|
170
170
|
#
|
171
171
|
# # RSpec
|
@@ -193,7 +193,7 @@ module Shoulda
|
|
193
193
|
# attribute.
|
194
194
|
#
|
195
195
|
# class User < ActiveRecord::Base
|
196
|
-
#
|
196
|
+
# validates :email, uniqueness: true
|
197
197
|
#
|
198
198
|
# def email=(value)
|
199
199
|
# super(value.downcase)
|
@@ -217,7 +217,7 @@ module Shoulda
|
|
217
217
|
# Use `allow_nil` to assert that the attribute allows nil.
|
218
218
|
#
|
219
219
|
# class Post < ActiveRecord::Base
|
220
|
-
#
|
220
|
+
# validates :author_id, uniqueness: true, allow_nil: true
|
221
221
|
# end
|
222
222
|
#
|
223
223
|
# # RSpec
|
@@ -237,7 +237,7 @@ module Shoulda
|
|
237
237
|
# Use `allow_blank` to assert that the attribute allows a blank value.
|
238
238
|
#
|
239
239
|
# class Post < ActiveRecord::Base
|
240
|
-
#
|
240
|
+
# validates :author_id, uniqueness: true, allow_blank: true
|
241
241
|
# end
|
242
242
|
#
|
243
243
|
# # RSpec
|
@@ -296,7 +296,7 @@ module Shoulda
|
|
296
296
|
end
|
297
297
|
|
298
298
|
def expects_to_allow_nil?
|
299
|
-
@options[:allow_nil]
|
299
|
+
@options[:allow_nil] == true
|
300
300
|
end
|
301
301
|
|
302
302
|
def allow_blank
|
@@ -305,7 +305,7 @@ module Shoulda
|
|
305
305
|
end
|
306
306
|
|
307
307
|
def expects_to_allow_blank?
|
308
|
-
@options[:allow_blank]
|
308
|
+
@options[:allow_blank] == true
|
309
309
|
end
|
310
310
|
|
311
311
|
def simple_description
|
@@ -324,14 +324,29 @@ module Shoulda
|
|
324
324
|
@given_record = given_record
|
325
325
|
@all_records = model.all
|
326
326
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
327
|
+
matches_presence_of_attribute? &&
|
328
|
+
matches_presence_of_scopes? &&
|
329
|
+
matches_scopes_configuration? &&
|
330
|
+
matches_uniqueness_without_scopes? &&
|
331
|
+
matches_uniqueness_with_case_sensitivity_strategy? &&
|
332
|
+
matches_uniqueness_with_scopes? &&
|
333
|
+
matches_allow_nil? &&
|
334
|
+
matches_allow_blank?
|
335
|
+
ensure
|
336
|
+
Uniqueness::TestModels.remove_all
|
337
|
+
end
|
338
|
+
|
339
|
+
def does_not_match?(given_record)
|
340
|
+
@given_record = given_record
|
341
|
+
@all_records = model.all
|
342
|
+
|
343
|
+
does_not_match_presence_of_scopes? ||
|
344
|
+
does_not_match_scopes_configuration? ||
|
345
|
+
does_not_match_uniqueness_without_scopes? ||
|
346
|
+
does_not_match_uniqueness_with_case_sensitivity_strategy? ||
|
347
|
+
does_not_match_uniqueness_with_scopes? ||
|
348
|
+
does_not_match_allow_nil? ||
|
349
|
+
does_not_match_allow_blank?
|
335
350
|
ensure
|
336
351
|
Uniqueness::TestModels.remove_all
|
337
352
|
end
|
@@ -386,26 +401,45 @@ module Shoulda
|
|
386
401
|
end
|
387
402
|
end
|
388
403
|
|
389
|
-
def
|
404
|
+
def matches_scopes_configuration?
|
390
405
|
if scopes_match?
|
391
406
|
true
|
392
407
|
else
|
393
|
-
@failure_reason = 'Expected the validation'
|
408
|
+
@failure_reason = 'Expected the validation '
|
394
409
|
|
395
410
|
if expected_scopes.empty?
|
396
|
-
@failure_reason << '
|
411
|
+
@failure_reason << 'not to be scoped to anything, '
|
397
412
|
else
|
398
|
-
@failure_reason << "
|
413
|
+
@failure_reason << "to be scoped to #{inspected_expected_scopes}, "
|
399
414
|
end
|
400
415
|
|
401
|
-
if actual_sets_of_scopes.
|
402
|
-
@failure_reason << '
|
416
|
+
if actual_sets_of_scopes.any?
|
417
|
+
@failure_reason << 'but it was scoped to '
|
418
|
+
@failure_reason << "#{inspected_actual_scopes} instead."
|
403
419
|
else
|
404
|
-
@failure_reason << '
|
420
|
+
@failure_reason << 'but it was not scoped to anything.'
|
421
|
+
end
|
422
|
+
|
423
|
+
false
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
def does_not_match_scopes_configuration?
|
428
|
+
if scopes_match?
|
429
|
+
@failure_reason = 'Expected the validation '
|
430
|
+
|
431
|
+
if expected_scopes.empty?
|
432
|
+
@failure_reason << 'to be scoped to nothing, '
|
433
|
+
@failure_reason << 'but it was scoped to '
|
405
434
|
@failure_reason << "#{inspected_actual_scopes} instead."
|
435
|
+
else
|
436
|
+
@failure_reason << 'not to be scoped to '
|
437
|
+
@failure_reason << inspected_expected_scopes
|
406
438
|
end
|
407
439
|
|
408
440
|
false
|
441
|
+
else
|
442
|
+
true
|
409
443
|
end
|
410
444
|
end
|
411
445
|
|
@@ -420,8 +454,8 @@ module Shoulda
|
|
420
454
|
|
421
455
|
def inspected_actual_scopes
|
422
456
|
inspected_actual_sets_of_scopes.to_sentence(
|
423
|
-
words_connector:
|
424
|
-
last_word_connector:
|
457
|
+
words_connector: ' and ',
|
458
|
+
last_word_connector: ', and'
|
425
459
|
)
|
426
460
|
end
|
427
461
|
|
@@ -447,22 +481,32 @@ module Shoulda
|
|
447
481
|
end.reject(&:empty?)
|
448
482
|
end
|
449
483
|
|
450
|
-
def
|
451
|
-
|
452
|
-
update_existing_record!(nil)
|
484
|
+
def matches_allow_nil?
|
485
|
+
!expects_to_allow_nil? || (
|
486
|
+
update_existing_record!(nil) &&
|
453
487
|
allows_value_of(nil, @expected_message)
|
454
|
-
|
455
|
-
|
456
|
-
|
488
|
+
)
|
489
|
+
end
|
490
|
+
|
491
|
+
def does_not_match_allow_nil?
|
492
|
+
expects_to_allow_nil? && (
|
493
|
+
update_existing_record!(nil) &&
|
494
|
+
(@failure_reason = nil || disallows_value_of(nil, @expected_message))
|
495
|
+
)
|
457
496
|
end
|
458
497
|
|
459
|
-
def
|
460
|
-
|
461
|
-
update_existing_record!('')
|
498
|
+
def matches_allow_blank?
|
499
|
+
!expects_to_allow_blank? || (
|
500
|
+
update_existing_record!('') &&
|
462
501
|
allows_value_of('', @expected_message)
|
463
|
-
|
464
|
-
|
465
|
-
|
502
|
+
)
|
503
|
+
end
|
504
|
+
|
505
|
+
def does_not_match_allow_blank?
|
506
|
+
expects_to_allow_blank? && (
|
507
|
+
update_existing_record!('') &&
|
508
|
+
(@failure_reason = nil || disallows_value_of('', @expected_message))
|
509
|
+
)
|
466
510
|
end
|
467
511
|
|
468
512
|
def existing_record
|
@@ -515,13 +559,16 @@ module Shoulda
|
|
515
559
|
# but that would break users' existing tests
|
516
560
|
existing_record.save(validate: false)
|
517
561
|
end
|
562
|
+
|
563
|
+
true
|
518
564
|
end
|
519
565
|
|
520
566
|
def arbitrary_non_blank_value
|
567
|
+
non_blank_value = dummy_value_for(@attribute)
|
521
568
|
limit = column_limit_for(@attribute)
|
522
|
-
non_blank_value = 'an arbitrary value'
|
523
569
|
|
524
|
-
|
570
|
+
is_string_value = non_blank_value.is_a?(String)
|
571
|
+
if is_string_value && limit && limit < non_blank_value.length
|
525
572
|
'x' * limit
|
526
573
|
else
|
527
574
|
non_blank_value
|
@@ -547,7 +594,7 @@ module Shoulda
|
|
547
594
|
@new_record
|
548
595
|
end
|
549
596
|
|
550
|
-
def
|
597
|
+
def matches_presence_of_attribute?
|
551
598
|
if attribute_present_on_model?
|
552
599
|
true
|
553
600
|
else
|
@@ -557,20 +604,32 @@ module Shoulda
|
|
557
604
|
end
|
558
605
|
end
|
559
606
|
|
607
|
+
def does_not_match_presence_of_attribute?
|
608
|
+
if attribute_present_on_model?
|
609
|
+
@failure_reason =
|
610
|
+
":#{attribute} seems to be an attribute on #{model.name}."
|
611
|
+
false
|
612
|
+
else
|
613
|
+
true
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
560
617
|
def attribute_present_on_model?
|
561
618
|
model.method_defined?("#{attribute}=") ||
|
562
619
|
model.columns_hash.key?(attribute.to_s)
|
563
620
|
end
|
564
621
|
|
565
|
-
def
|
566
|
-
if
|
622
|
+
def matches_presence_of_scopes?
|
623
|
+
if scopes_missing_on_model.none?
|
567
624
|
true
|
568
625
|
else
|
626
|
+
inspected_scopes = scopes_missing_on_model.map(&:inspect)
|
627
|
+
|
569
628
|
reason = ''
|
570
629
|
|
571
|
-
reason <<
|
630
|
+
reason << inspected_scopes.to_sentence
|
572
631
|
|
573
|
-
if
|
632
|
+
if inspected_scopes.many?
|
574
633
|
reason << " do not seem to be attributes"
|
575
634
|
else
|
576
635
|
reason << " does not seem to be an attribute"
|
@@ -584,8 +643,34 @@ module Shoulda
|
|
584
643
|
end
|
585
644
|
end
|
586
645
|
|
587
|
-
def
|
588
|
-
scopes_missing_on_model.
|
646
|
+
def does_not_match_presence_of_scopes?
|
647
|
+
if scopes_missing_on_model.any?
|
648
|
+
true
|
649
|
+
else
|
650
|
+
inspected_scopes = scopes_present_on_model.map(&:inspect)
|
651
|
+
|
652
|
+
reason = ''
|
653
|
+
|
654
|
+
reason << inspected_scopes.to_sentence
|
655
|
+
|
656
|
+
if inspected_scopes.many?
|
657
|
+
reason << " seem to be attributes"
|
658
|
+
else
|
659
|
+
reason << " seems to be an attribute"
|
660
|
+
end
|
661
|
+
|
662
|
+
reason << " on #{model.name}."
|
663
|
+
|
664
|
+
@failure_reason = reason
|
665
|
+
|
666
|
+
false
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
def scopes_present_on_model
|
671
|
+
@_present_scopes ||= expected_scopes.select do |scope|
|
672
|
+
model.method_defined?("#{scope}=")
|
673
|
+
end
|
589
674
|
end
|
590
675
|
|
591
676
|
def scopes_missing_on_model
|
@@ -594,20 +679,26 @@ module Shoulda
|
|
594
679
|
end
|
595
680
|
end
|
596
681
|
|
597
|
-
def
|
598
|
-
|
682
|
+
def matches_uniqueness_without_scopes?
|
683
|
+
if existing_value_read.blank?
|
684
|
+
update_existing_record!(arbitrary_non_blank_value)
|
685
|
+
end
|
686
|
+
|
687
|
+
disallows_value_of(existing_value_read, @expected_message)
|
599
688
|
end
|
600
689
|
|
601
|
-
def
|
690
|
+
def does_not_match_uniqueness_without_scopes?
|
691
|
+
@failure_reason = nil
|
692
|
+
|
602
693
|
if existing_value_read.blank?
|
603
694
|
update_existing_record!(arbitrary_non_blank_value)
|
604
695
|
end
|
605
696
|
|
606
|
-
|
697
|
+
allows_value_of(existing_value_read, @expected_message)
|
607
698
|
end
|
608
699
|
|
609
|
-
def
|
610
|
-
if
|
700
|
+
def matches_uniqueness_with_case_sensitivity_strategy?
|
701
|
+
if should_test_case_sensitivity?
|
611
702
|
value = existing_value_read
|
612
703
|
swapcased_value = value.swapcase
|
613
704
|
|
@@ -629,7 +720,32 @@ module Shoulda
|
|
629
720
|
end
|
630
721
|
end
|
631
722
|
|
632
|
-
def
|
723
|
+
def does_not_match_uniqueness_with_case_sensitivity_strategy?
|
724
|
+
if should_test_case_sensitivity?
|
725
|
+
@failure_reason = nil
|
726
|
+
|
727
|
+
value = existing_value_read
|
728
|
+
swapcased_value = value.swapcase
|
729
|
+
|
730
|
+
if case_sensitivity_strategy == :sensitive
|
731
|
+
disallows_value_of(swapcased_value, @expected_message)
|
732
|
+
else
|
733
|
+
if value == swapcased_value
|
734
|
+
raise NonCaseSwappableValueError.create(
|
735
|
+
model: model,
|
736
|
+
attribute: @attribute,
|
737
|
+
value: value
|
738
|
+
)
|
739
|
+
end
|
740
|
+
|
741
|
+
allows_value_of(swapcased_value, @expected_message)
|
742
|
+
end
|
743
|
+
else
|
744
|
+
true
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
def should_test_case_sensitivity?
|
633
749
|
case_sensitivity_strategy != :ignore &&
|
634
750
|
existing_value_read.respond_to?(:swapcase) &&
|
635
751
|
!existing_value_read.empty?
|
@@ -641,30 +757,42 @@ module Shoulda
|
|
641
757
|
false
|
642
758
|
end
|
643
759
|
|
644
|
-
def
|
645
|
-
|
646
|
-
|
647
|
-
else
|
760
|
+
def matches_uniqueness_with_scopes?
|
761
|
+
expected_scopes.none? ||
|
762
|
+
all_scopes_are_booleans? ||
|
648
763
|
expected_scopes.all? do |scope|
|
649
|
-
|
650
|
-
|
651
|
-
next_value =
|
652
|
-
if previous_value.blank?
|
653
|
-
dummy_value_for(scope)
|
654
|
-
else
|
655
|
-
next_value_for(scope, previous_value)
|
656
|
-
end
|
657
|
-
|
658
|
-
set_attribute_on_new_record!(scope, next_value)
|
659
|
-
|
660
|
-
if allows_value_of(existing_value_read, @expected_message)
|
661
|
-
set_attribute_on_new_record!(scope, previous_value)
|
662
|
-
true
|
663
|
-
else
|
664
|
-
false
|
764
|
+
setting_next_value_for(scope) do
|
765
|
+
allows_value_of(existing_value_read, @expected_message)
|
665
766
|
end
|
666
767
|
end
|
667
|
-
|
768
|
+
end
|
769
|
+
|
770
|
+
def does_not_match_uniqueness_with_scopes?
|
771
|
+
expected_scopes.any? &&
|
772
|
+
!all_scopes_are_booleans? &&
|
773
|
+
expected_scopes.any? do |scope|
|
774
|
+
setting_next_value_for(scope) do
|
775
|
+
@failure_reason = nil
|
776
|
+
disallows_value_of(existing_value_read, @expected_message)
|
777
|
+
end
|
778
|
+
end
|
779
|
+
end
|
780
|
+
|
781
|
+
def setting_next_value_for(scope)
|
782
|
+
previous_value = @all_records.map(&scope).compact.max
|
783
|
+
|
784
|
+
next_value =
|
785
|
+
if previous_value.blank?
|
786
|
+
dummy_value_for(scope)
|
787
|
+
else
|
788
|
+
next_value_for(scope, previous_value)
|
789
|
+
end
|
790
|
+
|
791
|
+
set_attribute_on_new_record!(scope, next_value)
|
792
|
+
|
793
|
+
yield
|
794
|
+
ensure
|
795
|
+
set_attribute_on_new_record!(scope, previous_value)
|
668
796
|
end
|
669
797
|
|
670
798
|
def dummy_value_for(scope)
|