shoulda-matchers 5.1.0 → 6.4.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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +41 -18
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +7 -9
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +13 -15
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +46 -1
- data/lib/shoulda/matchers/active_model/comparison_matcher.rb +157 -0
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +7 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +3 -5
- data/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +53 -0
- data/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
- data/lib/shoulda/matchers/active_model/qualifiers.rb +1 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +2 -7
- data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +532 -0
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +5 -5
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +29 -14
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +65 -10
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +76 -86
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +29 -4
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +6 -7
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +6 -0
- data/lib/shoulda/matchers/active_model/validator.rb +4 -0
- data/lib/shoulda/matchers/active_model.rb +4 -1
- data/lib/shoulda/matchers/active_record/association_matcher.rb +543 -15
- data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +34 -4
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +9 -1
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -0
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +4 -0
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +23 -19
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +27 -23
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +338 -30
- data/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +46 -6
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +24 -13
- data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +3 -5
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
- data/lib/shoulda/matchers/active_record/uniqueness/model.rb +13 -1
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +82 -70
- data/lib/shoulda/matchers/active_record.rb +2 -0
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -6
- data/lib/shoulda/matchers/doublespeak/world.rb +2 -6
- data/lib/shoulda/matchers/doublespeak.rb +0 -1
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +13 -15
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +7 -5
- data/lib/shoulda/matchers/integrations/libraries/routing.rb +5 -3
- data/lib/shoulda/matchers/rails_shim.rb +22 -6
- data/lib/shoulda/matchers/util/word_wrap.rb +2 -2
- data/lib/shoulda/matchers/util.rb +18 -20
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers.rb +2 -2
- data/shoulda-matchers.gemspec +2 -2
- metadata +15 -9
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +0 -157
@@ -144,6 +144,28 @@ module Shoulda
|
|
144
144
|
# with_foreign_key('country_id')
|
145
145
|
# end
|
146
146
|
#
|
147
|
+
# ##### with_foreign_type
|
148
|
+
#
|
149
|
+
# Use `with_foreign_type` to test usage of the `:foreign_type` option.
|
150
|
+
#
|
151
|
+
# class Visitor < ActiveRecord::Base
|
152
|
+
# belongs_to :location, foreign_type: 'facility_type', polymorphic: true
|
153
|
+
# end
|
154
|
+
#
|
155
|
+
# # RSpec
|
156
|
+
# RSpec.describe Visitor, type: :model do
|
157
|
+
# it do
|
158
|
+
# should belong_to(:location).
|
159
|
+
# with_foreign_type('facility_type')
|
160
|
+
# end
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# # Minitest (Shoulda)
|
164
|
+
# class VisitorTest < ActiveSupport::TestCase
|
165
|
+
# should belong_to(:location).
|
166
|
+
# with_foreign_type('facility_type')
|
167
|
+
# end
|
168
|
+
#
|
147
169
|
# ##### dependent
|
148
170
|
#
|
149
171
|
# Use `dependent` to assert that the `:dependent` option was specified.
|
@@ -217,6 +239,36 @@ module Shoulda
|
|
217
239
|
# should belong_to(:organization).touch(true)
|
218
240
|
# end
|
219
241
|
#
|
242
|
+
# ##### strict_loading
|
243
|
+
#
|
244
|
+
# Use `strict_loading` to assert that the `:strict_loading` option was specified.
|
245
|
+
#
|
246
|
+
# class Organization < ActiveRecord::Base
|
247
|
+
# has_many :people, strict_loading: true
|
248
|
+
# end
|
249
|
+
#
|
250
|
+
# # RSpec
|
251
|
+
# RSpec.describe Organization, type: :model do
|
252
|
+
# it { should have_many(:people).strict_loading(true) }
|
253
|
+
# end
|
254
|
+
#
|
255
|
+
# # Minitest (Shoulda)
|
256
|
+
# class OrganizationTest < ActiveSupport::TestCase
|
257
|
+
# should have_many(:people).strict_loading(true)
|
258
|
+
# end
|
259
|
+
#
|
260
|
+
# Default value is true when no argument is specified
|
261
|
+
#
|
262
|
+
# # RSpec
|
263
|
+
# RSpec.describe Organization, type: :model do
|
264
|
+
# it { should have_many(:people).strict_loading }
|
265
|
+
# end
|
266
|
+
#
|
267
|
+
# # Minitest (Shoulda)
|
268
|
+
# class OrganizationTest < ActiveSupport::TestCase
|
269
|
+
# should have_many(:people).strict_loading
|
270
|
+
# end
|
271
|
+
#
|
220
272
|
# ##### autosave
|
221
273
|
#
|
222
274
|
# Use `autosave` to assert that the `:autosave` option was specified.
|
@@ -326,6 +378,316 @@ module Shoulda
|
|
326
378
|
AssociationMatcher.new(:belongs_to, name)
|
327
379
|
end
|
328
380
|
|
381
|
+
# The `have_delegated_type` matcher is used to ensure that a `belong_to` association
|
382
|
+
# exists on your model using the delegated_type macro.
|
383
|
+
#
|
384
|
+
# class Vehicle < ActiveRecord::Base
|
385
|
+
# delegated_type :drivable, types: %w(Car Truck)
|
386
|
+
# end
|
387
|
+
#
|
388
|
+
# # RSpec
|
389
|
+
# RSpec.describe Vehicle, type: :model do
|
390
|
+
# it { should have_delegated_type(:drivable) }
|
391
|
+
# end
|
392
|
+
#
|
393
|
+
# # Minitest (Shoulda)
|
394
|
+
# class VehicleTest < ActiveSupport::TestCase
|
395
|
+
# should have_delegated_type(:drivable)
|
396
|
+
# end
|
397
|
+
#
|
398
|
+
# #### Qualifiers
|
399
|
+
#
|
400
|
+
# ##### types
|
401
|
+
#
|
402
|
+
# Use `types` to test the types that are allowed for the association.
|
403
|
+
#
|
404
|
+
# class Vehicle < ActiveRecord::Base
|
405
|
+
# delegated_type :drivable, types: %w(Car Truck)
|
406
|
+
# end
|
407
|
+
#
|
408
|
+
# # RSpec
|
409
|
+
# RSpec.describe Vehicle, type: :model do
|
410
|
+
# it do
|
411
|
+
# should have_delegated_type(:drivable).
|
412
|
+
# types(%w(Car Truck))
|
413
|
+
# end
|
414
|
+
# end
|
415
|
+
#
|
416
|
+
# # Minitest (Shoulda)
|
417
|
+
# class VehicleTest < ActiveSupport::TestCase
|
418
|
+
# should have_delegated_type(:drivable).
|
419
|
+
# types(%w(Car Truck))
|
420
|
+
# end
|
421
|
+
#
|
422
|
+
# ##### conditions
|
423
|
+
#
|
424
|
+
# Use `conditions` if your association is defined with a scope that sets
|
425
|
+
# the `where` clause.
|
426
|
+
#
|
427
|
+
# class Vehicle < ActiveRecord::Base
|
428
|
+
# delegated_type :drivable, types: %w(Car Truck), scope: -> { where(with_wheels: true) }
|
429
|
+
# end
|
430
|
+
#
|
431
|
+
# # RSpec
|
432
|
+
# RSpec.describe Vehicle, type: :model do
|
433
|
+
# it do
|
434
|
+
# should have_delegated_type(:drivable).
|
435
|
+
# conditions(with_wheels: true)
|
436
|
+
# end
|
437
|
+
# end
|
438
|
+
#
|
439
|
+
# # Minitest (Shoulda)
|
440
|
+
# class VehicleTest < ActiveSupport::TestCase
|
441
|
+
# should have_delegated_type(:drivable).
|
442
|
+
# conditions(everyone_is_perfect: false)
|
443
|
+
# end
|
444
|
+
#
|
445
|
+
# ##### order
|
446
|
+
#
|
447
|
+
# Use `order` if your association is defined with a scope that sets the
|
448
|
+
# `order` clause.
|
449
|
+
#
|
450
|
+
# class Person < ActiveRecord::Base
|
451
|
+
# delegated_type :drivable, types: %w(Car Truck), scope: -> { order('wheels desc') }
|
452
|
+
# end
|
453
|
+
#
|
454
|
+
# # RSpec
|
455
|
+
# RSpec.describe Vehicle, type: :model do
|
456
|
+
# it { should have_delegated_type(:drivable).order('wheels desc') }
|
457
|
+
# end
|
458
|
+
#
|
459
|
+
# # Minitest (Shoulda)
|
460
|
+
# class VehicleTest < ActiveSupport::TestCase
|
461
|
+
# should have_delegated_type(:drivable).order('wheels desc')
|
462
|
+
# end
|
463
|
+
#
|
464
|
+
# ##### with_primary_key
|
465
|
+
#
|
466
|
+
# Use `with_primary_key` to test usage of the `:primary_key` option.
|
467
|
+
#
|
468
|
+
# class Vehicle < ActiveRecord::Base
|
469
|
+
# delegated_type :drivable, types: %w(Car Truck), primary_key: 'vehicle_id'
|
470
|
+
# end
|
471
|
+
#
|
472
|
+
# # RSpec
|
473
|
+
# RSpec.describe Vehicle, type: :model do
|
474
|
+
# it do
|
475
|
+
# should have_delegated_type(:drivable).
|
476
|
+
# with_primary_key('vehicle_id')
|
477
|
+
# end
|
478
|
+
# end
|
479
|
+
#
|
480
|
+
# # Minitest (Shoulda)
|
481
|
+
# class VehicleTest < ActiveSupport::TestCase
|
482
|
+
# should have_delegated_type(:drivable).
|
483
|
+
# with_primary_key('vehicle_id')
|
484
|
+
# end
|
485
|
+
#
|
486
|
+
# ##### with_foreign_key
|
487
|
+
#
|
488
|
+
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
|
489
|
+
#
|
490
|
+
# class Vehicle < ActiveRecord::Base
|
491
|
+
# delegated_type :drivable, types: %w(Car Truck), foreign_key: 'drivable_uuid'
|
492
|
+
# end
|
493
|
+
#
|
494
|
+
# # RSpec
|
495
|
+
# RSpec.describe Vehicle, type: :model do
|
496
|
+
# it do
|
497
|
+
# should have_delegated_type(:drivable).
|
498
|
+
# with_foreign_key('drivable_uuid')
|
499
|
+
# end
|
500
|
+
# end
|
501
|
+
#
|
502
|
+
# # Minitest (Shoulda)
|
503
|
+
# class VehicleTest < ActiveSupport::TestCase
|
504
|
+
# should have_delegated_type(:drivable).
|
505
|
+
# with_foreign_key('drivable_uuid')
|
506
|
+
# end
|
507
|
+
#
|
508
|
+
# ##### dependent
|
509
|
+
#
|
510
|
+
# Use `dependent` to assert that the `:dependent` option was specified.
|
511
|
+
#
|
512
|
+
# class Vehicle < ActiveRecord::Base
|
513
|
+
# delegated_type :drivable, types: %w(Car Truck), dependent: :destroy
|
514
|
+
# end
|
515
|
+
#
|
516
|
+
# # RSpec
|
517
|
+
# RSpec.describe Vehicle, type: :model do
|
518
|
+
# it { should have_delegated_type(:drivable).dependent(:destroy) }
|
519
|
+
# end
|
520
|
+
#
|
521
|
+
# # Minitest (Shoulda)
|
522
|
+
# class VehicleTest < ActiveSupport::TestCase
|
523
|
+
# should have_delegated_type(:drivable).dependent(:destroy)
|
524
|
+
# end
|
525
|
+
#
|
526
|
+
# To assert that *any* `:dependent` option was specified, use `true`:
|
527
|
+
#
|
528
|
+
# # RSpec
|
529
|
+
# RSpec.describe Vehicle, type: :model do
|
530
|
+
# it { should have_delegated_type(:drivable).dependent(true) }
|
531
|
+
# end
|
532
|
+
#
|
533
|
+
# To assert that *no* `:dependent` option was specified, use `false`:
|
534
|
+
#
|
535
|
+
# class Vehicle < ActiveRecord::Base
|
536
|
+
# delegated_type :drivable, types: %w(Car Truck)
|
537
|
+
# end
|
538
|
+
#
|
539
|
+
# # RSpec
|
540
|
+
# RSpec.describe Vehicle, type: :model do
|
541
|
+
# it { should have_delegated_type(:drivable).dependent(false) }
|
542
|
+
# end
|
543
|
+
#
|
544
|
+
# ##### counter_cache
|
545
|
+
#
|
546
|
+
# Use `counter_cache` to assert that the `:counter_cache` option was
|
547
|
+
# specified.
|
548
|
+
#
|
549
|
+
# class Vehicle < ActiveRecord::Base
|
550
|
+
# delegated_type :drivable, types: %w(Car Truck), counter_cache: true
|
551
|
+
# end
|
552
|
+
#
|
553
|
+
# # RSpec
|
554
|
+
# RSpec.describe Vehicle, type: :model do
|
555
|
+
# it { should have_delegated_type(:drivable).counter_cache(true) }
|
556
|
+
# end
|
557
|
+
#
|
558
|
+
# # Minitest (Shoulda)
|
559
|
+
# class VehicleTest < ActiveSupport::TestCase
|
560
|
+
# should have_delegated_type(:drivable).counter_cache(true)
|
561
|
+
# end
|
562
|
+
#
|
563
|
+
# ##### touch
|
564
|
+
#
|
565
|
+
# Use `touch` to assert that the `:touch` option was specified.
|
566
|
+
#
|
567
|
+
# class Vehicle < ActiveRecord::Base
|
568
|
+
# delegated_type :drivable, types: %w(Car Truck), touch: true
|
569
|
+
# end
|
570
|
+
#
|
571
|
+
# # RSpec
|
572
|
+
# RSpec.describe Vehicle, type: :model do
|
573
|
+
# it { should have_delegated_type(:drivable).touch(true) }
|
574
|
+
# end
|
575
|
+
#
|
576
|
+
# # Minitest (Shoulda)
|
577
|
+
# class VehicleTest < ActiveSupport::TestCase
|
578
|
+
# should have_delegated_type(:drivable).touch(true)
|
579
|
+
# end
|
580
|
+
#
|
581
|
+
# ##### autosave
|
582
|
+
#
|
583
|
+
# Use `autosave` to assert that the `:autosave` option was specified.
|
584
|
+
#
|
585
|
+
# class Vehicle < ActiveRecord::Base
|
586
|
+
# delegated_type :drivable, types: %w(Car Truck), autosave: true
|
587
|
+
# end
|
588
|
+
#
|
589
|
+
# # RSpec
|
590
|
+
# RSpec.describe Vehicle, type: :model do
|
591
|
+
# it { should have_delegated_type(:drivable).autosave(true) }
|
592
|
+
# end
|
593
|
+
#
|
594
|
+
# # Minitest (Shoulda)
|
595
|
+
# class VehicleTest < ActiveSupport::TestCase
|
596
|
+
# should have_delegated_type(:drivable).autosave(true)
|
597
|
+
# end
|
598
|
+
#
|
599
|
+
# ##### inverse_of
|
600
|
+
#
|
601
|
+
# Use `inverse_of` to assert that the `:inverse_of` option was specified.
|
602
|
+
#
|
603
|
+
# class Vehicle < ActiveRecord::Base
|
604
|
+
# delegated_type :drivable, types: %w(Car Truck), inverse_of: :vehicle
|
605
|
+
# end
|
606
|
+
#
|
607
|
+
# # RSpec
|
608
|
+
# describe Vehicle
|
609
|
+
# it { should have_delegated_type(:drivable).inverse_of(:vehicle) }
|
610
|
+
# end
|
611
|
+
#
|
612
|
+
# # Minitest (Shoulda)
|
613
|
+
# class VehicleTest < ActiveSupport::TestCase
|
614
|
+
# should have_delegated_type(:drivable).inverse_of(:vehicle)
|
615
|
+
# end
|
616
|
+
#
|
617
|
+
# ##### required
|
618
|
+
#
|
619
|
+
# Use `required` to assert that the association is not allowed to be nil.
|
620
|
+
# (Enabled by default in Rails 5+.)
|
621
|
+
#
|
622
|
+
# class Vehicle < ActiveRecord::Base
|
623
|
+
# delegated_type :drivable, types: %w(Car Truck), required: true
|
624
|
+
# end
|
625
|
+
#
|
626
|
+
# # RSpec
|
627
|
+
# describe Vehicle
|
628
|
+
# it { should have_delegated_type(:drivable).required }
|
629
|
+
# end
|
630
|
+
#
|
631
|
+
# # Minitest (Shoulda)
|
632
|
+
# class VehicleTest < ActiveSupport::TestCase
|
633
|
+
# should have_delegated_type(:drivable).required
|
634
|
+
# end
|
635
|
+
#
|
636
|
+
# ##### without_validating_presence
|
637
|
+
#
|
638
|
+
# Use `without_validating_presence` with `belong_to` to prevent the
|
639
|
+
# matcher from checking whether the association disallows nil (Rails 5+
|
640
|
+
# only). This can be helpful if you have a custom hook that always sets
|
641
|
+
# the association to a meaningful value:
|
642
|
+
#
|
643
|
+
# class Vehicle < ActiveRecord::Base
|
644
|
+
# delegated_type :drivable, types: %w(Car Truck)
|
645
|
+
#
|
646
|
+
# before_validation :autoassign_drivable
|
647
|
+
#
|
648
|
+
# private
|
649
|
+
#
|
650
|
+
# def autoassign_drivable
|
651
|
+
# self.drivable = Car.create!
|
652
|
+
# end
|
653
|
+
# end
|
654
|
+
#
|
655
|
+
# # RSpec
|
656
|
+
# describe Vehicle
|
657
|
+
# it { should have_delegated_type(:drivable).without_validating_presence }
|
658
|
+
# end
|
659
|
+
#
|
660
|
+
# # Minitest (Shoulda)
|
661
|
+
# class VehicleTest < ActiveSupport::TestCase
|
662
|
+
# should have_delegated_type(:drivable).without_validating_presence
|
663
|
+
# end
|
664
|
+
#
|
665
|
+
# ##### optional
|
666
|
+
#
|
667
|
+
# Use `optional` to assert that the association is allowed to be nil.
|
668
|
+
# (Rails 5+ only.)
|
669
|
+
#
|
670
|
+
# class Vehicle < ActiveRecord::Base
|
671
|
+
# delegated_type :drivable, types: %w(Car Truck), optional: true
|
672
|
+
# end
|
673
|
+
#
|
674
|
+
# # RSpec
|
675
|
+
# describe Vehicle
|
676
|
+
# it { should have_delegated_type(:drivable).optional }
|
677
|
+
# end
|
678
|
+
#
|
679
|
+
# # Minitest (Shoulda)
|
680
|
+
# class VehicleTest < ActiveSupport::TestCase
|
681
|
+
# should have_delegated_type(:drivable).optional
|
682
|
+
# end
|
683
|
+
#
|
684
|
+
# @return [AssociationMatcher]
|
685
|
+
#
|
686
|
+
|
687
|
+
def have_delegated_type(name)
|
688
|
+
AssociationMatcher.new(:belongs_to, name)
|
689
|
+
end
|
690
|
+
|
329
691
|
# The `have_many` matcher is used to test that a `has_many` or `has_many
|
330
692
|
# :through` association exists on your model.
|
331
693
|
#
|
@@ -455,6 +817,24 @@ module Shoulda
|
|
455
817
|
# should have_many(:worries).with_foreign_key('worrier_id')
|
456
818
|
# end
|
457
819
|
#
|
820
|
+
# ##### with_foreign_type
|
821
|
+
#
|
822
|
+
# Use `with_foreign_type` to test usage of the `:foreign_type` option.
|
823
|
+
#
|
824
|
+
# class Hotel < ActiveRecord::Base
|
825
|
+
# has_many :visitors, foreign_key: 'facility_type', as: :location
|
826
|
+
# end
|
827
|
+
#
|
828
|
+
# # RSpec
|
829
|
+
# RSpec.describe Hotel, type: :model do
|
830
|
+
# it { should have_many(:visitors).with_foreign_type('facility_type') }
|
831
|
+
# end
|
832
|
+
#
|
833
|
+
# # Minitest (Shoulda)
|
834
|
+
# class HotelTest < ActiveSupport::TestCase
|
835
|
+
# should have_many(:visitors).with_foreign_type('facility_type')
|
836
|
+
# end
|
837
|
+
#
|
458
838
|
# ##### dependent
|
459
839
|
#
|
460
840
|
# Use `dependent` to assert that the `:dependent` option was specified.
|
@@ -726,6 +1106,24 @@ module Shoulda
|
|
726
1106
|
# should have_one(:job).with_foreign_key('worker_id')
|
727
1107
|
# end
|
728
1108
|
#
|
1109
|
+
# ##### with_foreign_type
|
1110
|
+
#
|
1111
|
+
# Use `with_foreign_type` to test usage of the `:foreign_type` option.
|
1112
|
+
#
|
1113
|
+
# class Hotel < ActiveRecord::Base
|
1114
|
+
# has_one :special_guest, foreign_type: 'facility_type', as: :location
|
1115
|
+
# end
|
1116
|
+
#
|
1117
|
+
# # RSpec
|
1118
|
+
# RSpec.describe Hotel, type: :model do
|
1119
|
+
# it { should have_one(:special_guest).with_foreign_type('facility_type') }
|
1120
|
+
# end
|
1121
|
+
#
|
1122
|
+
# # Minitest (Shoulda)
|
1123
|
+
# class HotelTest < ActiveSupport::TestCase
|
1124
|
+
# should have_one(:special_guest).with_foreign_type('facility_type')
|
1125
|
+
# end
|
1126
|
+
#
|
729
1127
|
# ##### through
|
730
1128
|
#
|
731
1129
|
# Use `through` to test usage of the `:through` option. This asserts that
|
@@ -1068,6 +1466,11 @@ module Shoulda
|
|
1068
1466
|
self
|
1069
1467
|
end
|
1070
1468
|
|
1469
|
+
def types(types)
|
1470
|
+
@options[:types] = types
|
1471
|
+
self
|
1472
|
+
end
|
1473
|
+
|
1071
1474
|
def autosave(autosave)
|
1072
1475
|
@options[:autosave] = autosave
|
1073
1476
|
self
|
@@ -1088,11 +1491,21 @@ module Shoulda
|
|
1088
1491
|
self
|
1089
1492
|
end
|
1090
1493
|
|
1494
|
+
def with_foreign_type(foreign_type)
|
1495
|
+
@options[:foreign_type] = foreign_type
|
1496
|
+
self
|
1497
|
+
end
|
1498
|
+
|
1091
1499
|
def with_primary_key(primary_key)
|
1092
1500
|
@options[:primary_key] = primary_key
|
1093
1501
|
self
|
1094
1502
|
end
|
1095
1503
|
|
1504
|
+
def with_query_constraints(query_constraints)
|
1505
|
+
@options[:query_constraints] = query_constraints
|
1506
|
+
self
|
1507
|
+
end
|
1508
|
+
|
1096
1509
|
def required(required = true)
|
1097
1510
|
remove_submatcher(AssociationMatchers::OptionalMatcher)
|
1098
1511
|
add_submatcher(
|
@@ -1123,6 +1536,11 @@ module Shoulda
|
|
1123
1536
|
self
|
1124
1537
|
end
|
1125
1538
|
|
1539
|
+
def strict_loading(strict_loading = true)
|
1540
|
+
@options[:strict_loading] = strict_loading
|
1541
|
+
self
|
1542
|
+
end
|
1543
|
+
|
1126
1544
|
def join_table(join_table_name)
|
1127
1545
|
@options[:join_table_name] = join_table_name
|
1128
1546
|
self
|
@@ -1155,8 +1573,10 @@ module Shoulda
|
|
1155
1573
|
macro_correct? &&
|
1156
1574
|
validate_inverse_of_through_association &&
|
1157
1575
|
(polymorphic? || class_exists?) &&
|
1576
|
+
foreign_type_matches? &&
|
1158
1577
|
foreign_key_exists? &&
|
1159
1578
|
primary_key_exists? &&
|
1579
|
+
query_constraints_exists? &&
|
1160
1580
|
class_name_correct? &&
|
1161
1581
|
join_table_correct? &&
|
1162
1582
|
autosave_correct? &&
|
@@ -1164,6 +1584,8 @@ module Shoulda
|
|
1164
1584
|
conditions_correct? &&
|
1165
1585
|
validate_correct? &&
|
1166
1586
|
touch_correct? &&
|
1587
|
+
types_correct? &&
|
1588
|
+
strict_loading_correct? &&
|
1167
1589
|
submatchers_match?
|
1168
1590
|
end
|
1169
1591
|
|
@@ -1258,29 +1680,65 @@ module Shoulda
|
|
1258
1680
|
false
|
1259
1681
|
end
|
1260
1682
|
|
1261
|
-
def
|
1262
|
-
macro == :belongs_to ||
|
1263
|
-
|
1683
|
+
def macro_is_not_through?
|
1684
|
+
macro == :belongs_to || has_association_not_through?
|
1685
|
+
end
|
1686
|
+
|
1687
|
+
def has_association_not_through?
|
1688
|
+
[:has_many, :has_one].include?(macro) && !through?
|
1264
1689
|
end
|
1265
1690
|
|
1266
1691
|
def foreign_key_exists?
|
1267
1692
|
!(belongs_foreign_key_missing? || has_foreign_key_missing?)
|
1268
1693
|
end
|
1269
1694
|
|
1695
|
+
def foreign_type_matches?
|
1696
|
+
!options.key?(:foreign_type) || (
|
1697
|
+
!belongs_foreign_type_missing? &&
|
1698
|
+
!has_foreign_type_missing?
|
1699
|
+
)
|
1700
|
+
end
|
1701
|
+
|
1270
1702
|
def primary_key_exists?
|
1271
|
-
!
|
1703
|
+
!macro_is_not_through? || primary_key_correct?(model_class)
|
1704
|
+
end
|
1705
|
+
|
1706
|
+
def query_constraints_exists?
|
1707
|
+
!macro_is_not_through? || query_constraints_correct?
|
1708
|
+
end
|
1709
|
+
|
1710
|
+
def query_constraints_correct?
|
1711
|
+
if options.key?(:query_constraints)
|
1712
|
+
if option_verifier.correct_for_string?(:query_constraints, options[:query_constraints])
|
1713
|
+
true
|
1714
|
+
else
|
1715
|
+
@missing = "#{model_class} should have \:query_constraints"\
|
1716
|
+
" options set to #{options[:query_constraints]}"
|
1717
|
+
false
|
1718
|
+
end
|
1719
|
+
else
|
1720
|
+
true
|
1721
|
+
end
|
1272
1722
|
end
|
1273
1723
|
|
1274
1724
|
def belongs_foreign_key_missing?
|
1275
1725
|
macro == :belongs_to && !class_has_foreign_key?(model_class)
|
1276
1726
|
end
|
1277
1727
|
|
1728
|
+
def belongs_foreign_type_missing?
|
1729
|
+
macro == :belongs_to && !class_has_foreign_type?(model_class)
|
1730
|
+
end
|
1731
|
+
|
1278
1732
|
def has_foreign_key_missing?
|
1279
|
-
|
1280
|
-
!through? &&
|
1733
|
+
has_association_not_through? &&
|
1281
1734
|
!class_has_foreign_key?(associated_class)
|
1282
1735
|
end
|
1283
1736
|
|
1737
|
+
def has_foreign_type_missing?
|
1738
|
+
has_association_not_through? &&
|
1739
|
+
!class_has_foreign_type?(associated_class)
|
1740
|
+
end
|
1741
|
+
|
1284
1742
|
def class_name_correct?
|
1285
1743
|
if options.key?(:class_name)
|
1286
1744
|
if option_verifier.correct_for_constant?(
|
@@ -1299,10 +1757,7 @@ module Shoulda
|
|
1299
1757
|
end
|
1300
1758
|
|
1301
1759
|
def join_table_correct?
|
1302
|
-
if (
|
1303
|
-
macro != :has_and_belongs_to_many ||
|
1304
|
-
join_table_matcher.matches?(@subject)
|
1305
|
-
)
|
1760
|
+
if macro != :has_and_belongs_to_many || join_table_matcher.matches?(@subject)
|
1306
1761
|
true
|
1307
1762
|
else
|
1308
1763
|
@missing = join_table_matcher.failure_message
|
@@ -1393,6 +1848,45 @@ module Shoulda
|
|
1393
1848
|
end
|
1394
1849
|
end
|
1395
1850
|
|
1851
|
+
def types_correct?
|
1852
|
+
if options.key?(:types)
|
1853
|
+
types = options[:types]
|
1854
|
+
|
1855
|
+
correct = types.all? do |type|
|
1856
|
+
scope_name = type.tableize.tr('/', '_')
|
1857
|
+
singular = scope_name.singularize
|
1858
|
+
query = "#{singular}?"
|
1859
|
+
|
1860
|
+
Object.const_defined?(type) && @subject.respond_to?(query) &&
|
1861
|
+
@subject.respond_to?(singular)
|
1862
|
+
end
|
1863
|
+
|
1864
|
+
if correct
|
1865
|
+
true
|
1866
|
+
else
|
1867
|
+
@missing = "#{name} should have types: #{options[:types]}"
|
1868
|
+
false
|
1869
|
+
end
|
1870
|
+
else
|
1871
|
+
true
|
1872
|
+
end
|
1873
|
+
end
|
1874
|
+
|
1875
|
+
def strict_loading_correct?
|
1876
|
+
return true unless options.key?(:strict_loading)
|
1877
|
+
|
1878
|
+
if option_verifier.correct_for_boolean?(:strict_loading, options[:strict_loading])
|
1879
|
+
return true
|
1880
|
+
end
|
1881
|
+
|
1882
|
+
@missing = [
|
1883
|
+
"#{name} should have strict_loading set to ",
|
1884
|
+
options[:strict_loading].to_s,
|
1885
|
+
].join
|
1886
|
+
|
1887
|
+
false
|
1888
|
+
end
|
1889
|
+
|
1396
1890
|
def class_has_foreign_key?(klass)
|
1397
1891
|
@missing = validate_foreign_key(klass)
|
1398
1892
|
|
@@ -1407,6 +1901,22 @@ module Shoulda
|
|
1407
1901
|
end
|
1408
1902
|
end
|
1409
1903
|
|
1904
|
+
def class_has_foreign_type?(klass)
|
1905
|
+
if options.key?(:foreign_type) && !foreign_type_correct?
|
1906
|
+
@missing = foreign_type_failure_message(
|
1907
|
+
klass,
|
1908
|
+
options[:foreign_type],
|
1909
|
+
)
|
1910
|
+
|
1911
|
+
false
|
1912
|
+
elsif !has_column?(klass, foreign_type)
|
1913
|
+
@missing = foreign_type_failure_message(klass, foreign_type)
|
1914
|
+
false
|
1915
|
+
else
|
1916
|
+
true
|
1917
|
+
end
|
1918
|
+
end
|
1919
|
+
|
1410
1920
|
def has_column?(klass, column)
|
1411
1921
|
case column
|
1412
1922
|
when Array
|
@@ -1423,10 +1933,21 @@ module Shoulda
|
|
1423
1933
|
)
|
1424
1934
|
end
|
1425
1935
|
|
1936
|
+
def foreign_type_correct?
|
1937
|
+
option_verifier.correct_for_string?(
|
1938
|
+
:foreign_type,
|
1939
|
+
options[:foreign_type],
|
1940
|
+
)
|
1941
|
+
end
|
1942
|
+
|
1426
1943
|
def foreign_key_failure_message(klass, foreign_key)
|
1427
1944
|
"#{klass} does not have a #{foreign_key} foreign key."
|
1428
1945
|
end
|
1429
1946
|
|
1947
|
+
def foreign_type_failure_message(klass, foreign_type)
|
1948
|
+
"#{klass} does not have a #{foreign_type} foreign type."
|
1949
|
+
end
|
1950
|
+
|
1430
1951
|
def primary_key_correct?(klass)
|
1431
1952
|
if options.key?(:primary_key)
|
1432
1953
|
if option_verifier.correct_for_string?(
|
@@ -1457,11 +1978,10 @@ module Shoulda
|
|
1457
1978
|
end
|
1458
1979
|
|
1459
1980
|
def foreign_key_reflection
|
1460
|
-
if (
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
)
|
1981
|
+
if [:has_one, :has_many].include?(macro) &&
|
1982
|
+
reflection.options.include?(:inverse_of) &&
|
1983
|
+
reflection.options[:inverse_of] != false
|
1984
|
+
|
1465
1985
|
associated_class.reflect_on_association(
|
1466
1986
|
reflection.options[:inverse_of],
|
1467
1987
|
)
|
@@ -1470,6 +1990,14 @@ module Shoulda
|
|
1470
1990
|
end
|
1471
1991
|
end
|
1472
1992
|
|
1993
|
+
def foreign_type
|
1994
|
+
if [:has_one, :has_many].include?(macro)
|
1995
|
+
reflection.type
|
1996
|
+
else
|
1997
|
+
reflection.foreign_type
|
1998
|
+
end
|
1999
|
+
end
|
2000
|
+
|
1473
2001
|
def submatchers_match?
|
1474
2002
|
failing_submatchers.empty?
|
1475
2003
|
end
|