shoulda-matchers 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/.gitignore +8 -7
  2. data/.travis.yml +4 -0
  3. data/Appraisals +8 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +77 -66
  7. data/MIT-LICENSE +1 -1
  8. data/NEWS.md +63 -1
  9. data/README.md +189 -33
  10. data/Rakefile +6 -5
  11. data/features/rails_integration.feature +1 -1
  12. data/features/step_definitions/rails_steps.rb +7 -6
  13. data/gemfiles/3.0.gemfile +2 -2
  14. data/gemfiles/3.0.gemfile.lock +14 -5
  15. data/gemfiles/3.1.gemfile +2 -2
  16. data/gemfiles/3.1.gemfile.lock +14 -5
  17. data/gemfiles/3.2.gemfile +2 -2
  18. data/gemfiles/3.2.gemfile.lock +16 -7
  19. data/gemfiles/4.0.0.gemfile +2 -2
  20. data/gemfiles/4.0.0.gemfile.lock +15 -6
  21. data/gemfiles/4.0.1.gemfile +2 -2
  22. data/gemfiles/4.0.1.gemfile.lock +15 -6
  23. data/gemfiles/4.1.gemfile +19 -0
  24. data/gemfiles/4.1.gemfile.lock +176 -0
  25. data/lib/shoulda/matchers.rb +17 -1
  26. data/lib/shoulda/matchers/action_controller.rb +4 -2
  27. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +100 -0
  28. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
  29. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +4 -4
  30. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -1
  31. data/lib/shoulda/matchers/action_controller/route_matcher.rb +12 -12
  32. data/lib/shoulda/matchers/action_controller/route_params.rb +1 -1
  33. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +2 -1
  34. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +167 -0
  35. data/lib/shoulda/matchers/active_model.rb +4 -2
  36. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +23 -5
  37. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +0 -4
  38. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +66 -14
  39. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +8 -8
  40. data/lib/shoulda/matchers/active_model/errors.rb +40 -0
  41. data/lib/shoulda/matchers/active_model/helpers.rb +6 -6
  42. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +33 -14
  43. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +26 -0
  44. data/lib/shoulda/matchers/active_model/numericality_matchers/{odd_even_number_matcher.rb → numeric_type_matcher.rb} +9 -20
  45. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +26 -0
  46. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +5 -21
  47. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +1 -1
  48. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +71 -22
  49. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +6 -1
  50. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +25 -6
  51. data/lib/shoulda/matchers/active_record.rb +1 -0
  52. data/lib/shoulda/matchers/active_record/association_matcher.rb +67 -13
  53. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +40 -0
  54. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +24 -1
  55. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -1
  56. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +1 -1
  57. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
  58. data/lib/shoulda/matchers/assertion_error.rb +7 -2
  59. data/lib/shoulda/matchers/error.rb +24 -0
  60. data/lib/shoulda/matchers/independent.rb +10 -0
  61. data/lib/shoulda/matchers/independent/delegate_matcher.rb +157 -0
  62. data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +34 -0
  63. data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +36 -0
  64. data/lib/shoulda/matchers/integrations/rspec.rb +13 -14
  65. data/lib/shoulda/matchers/integrations/test_unit.rb +11 -9
  66. data/lib/shoulda/matchers/version.rb +1 -1
  67. data/lib/shoulda/matchers/warn.rb +7 -0
  68. data/shoulda-matchers.gemspec +2 -1
  69. data/spec/shoulda/matchers/action_controller/callback_matcher_spec.rb +79 -0
  70. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +3 -3
  71. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +11 -11
  72. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +21 -21
  73. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +10 -10
  74. data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +45 -18
  75. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +8 -8
  76. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +19 -19
  77. data/spec/shoulda/matchers/action_controller/route_params_spec.rb +6 -6
  78. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +11 -11
  79. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +44 -44
  80. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +205 -0
  81. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +24 -24
  82. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +37 -37
  83. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +17 -21
  84. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +24 -24
  85. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +173 -67
  86. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +40 -40
  87. data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +20 -20
  88. data/spec/shoulda/matchers/active_model/helpers_spec.rb +27 -25
  89. data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +126 -13
  90. data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
  91. data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
  92. data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +27 -26
  93. data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +15 -15
  94. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +8 -8
  95. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +9 -9
  96. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +229 -44
  97. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +44 -25
  98. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +110 -62
  99. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +19 -19
  100. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +30 -30
  101. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +378 -192
  102. data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +4 -0
  103. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +33 -33
  104. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +21 -17
  105. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +8 -8
  106. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +14 -14
  107. data/spec/shoulda/matchers/independent/delegate_matcher/stubbed_target_spec.rb +43 -0
  108. data/spec/shoulda/matchers/independent/delegate_matcher_spec.rb +184 -0
  109. data/spec/spec_helper.rb +4 -0
  110. data/spec/support/activemodel_helpers.rb +2 -2
  111. data/spec/support/capture_helpers.rb +19 -0
  112. data/spec/support/controller_builder.rb +22 -3
  113. data/spec/support/fail_with_message_including_matcher.rb +33 -0
  114. data/spec/support/model_builder.rb +1 -1
  115. data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
  116. data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
  117. data/spec/support/test_application.rb +23 -0
  118. metadata +90 -22
  119. checksums.yaml +0 -7
  120. data/spec/shoulda/matchers/active_model/numericality_matchers/odd_even_number_matcher_spec.rb +0 -97
  121. data/spec/support/shared_examples/numerical_submatcher_spec.rb +0 -23
@@ -3,11 +3,11 @@ require 'spec_helper'
3
3
  describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
4
4
  context '#allow_description' do
5
5
  it 'describes its attribute' do
6
- finder = build_finder(:attribute => :attr)
6
+ finder = build_finder(attribute: :attr)
7
7
 
8
8
  description = finder.allow_description('allowed values')
9
9
 
10
- description.should eq 'allow attr to be set to allowed values'
10
+ expect(description).to eq 'allow attr to be set to allowed values'
11
11
  end
12
12
  end
13
13
 
@@ -17,35 +17,35 @@ describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
17
17
 
18
18
  message = finder.expected_message_from('some message')
19
19
 
20
- message.should eq 'some message'
20
+ expect(message).to eq 'some message'
21
21
  end
22
22
  end
23
23
 
24
24
  context '#has_messages?' do
25
25
  it 'has messages when some validations fail' do
26
- finder = build_finder(:format => /abc/, :value => 'xyz')
26
+ finder = build_finder(format: /abc/, value: 'xyz')
27
27
 
28
28
  result = finder.has_messages?
29
29
 
30
- result.should be_true
30
+ expect(result).to eq true
31
31
  end
32
32
 
33
33
  it 'has no messages when all validations pass' do
34
- finder = build_finder(:format => /abc/, :value => 'abc')
34
+ finder = build_finder(format: /abc/, value: 'abc')
35
35
 
36
36
  result = finder.has_messages?
37
37
 
38
- result.should be_false
38
+ expect(result).to eq false
39
39
  end
40
40
  end
41
41
 
42
42
  context '#messages' do
43
43
  it 'returns errors for the given attribute' do
44
- finder = build_finder(:format => /abc/, :value => 'xyz')
44
+ finder = build_finder(format: /abc/, value: 'xyz')
45
45
 
46
46
  messages = finder.messages
47
47
 
48
- messages.should eq ['is invalid']
48
+ expect(messages).to eq ['is invalid']
49
49
  end
50
50
 
51
51
  it 'returns an empty array if there are no errors for the given attribute' do
@@ -53,30 +53,30 @@ describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
53
53
 
54
54
  messages = finder.messages
55
55
 
56
- messages.should == []
56
+ expect(messages).to eq([])
57
57
  end
58
58
  end
59
59
 
60
60
  context '#messages_description' do
61
61
  it 'describes errors for the given attribute' do
62
62
  finder = build_finder(
63
- :attribute => :attr,
64
- :format => /abc/,
65
- :value => 'xyz'
63
+ attribute: :attr,
64
+ format: /abc/,
65
+ value: 'xyz'
66
66
  )
67
67
 
68
68
  description = finder.messages_description
69
69
 
70
70
  expected_messages = ['attr is invalid ("xyz")']
71
- description.should eq "errors: #{expected_messages}"
71
+ expect(description).to eq "errors: #{expected_messages}"
72
72
  end
73
73
 
74
74
  it 'describes errors when there are none' do
75
- finder = build_finder(:format => /abc/, :value => 'abc')
75
+ finder = build_finder(format: /abc/, value: 'abc')
76
76
 
77
77
  description = finder.messages_description
78
78
 
79
- description.should eq 'no errors'
79
+ expect(description).to eq 'no errors'
80
80
  end
81
81
 
82
82
  it 'should not fetch attribute values for errors that were copied from an autosaved belongs_to association' do
@@ -88,7 +88,7 @@ describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
88
88
  finder = Shoulda::Matchers::ActiveModel::ValidationMessageFinder.new(instance, :attribute)
89
89
 
90
90
  expected_messages = ['association.association_attribute is invalid']
91
- finder.messages_description.should eq "errors: #{expected_messages}"
91
+ expect(finder.messages_description).to eq "errors: #{expected_messages}"
92
92
  end
93
93
 
94
94
  end
@@ -99,7 +99,7 @@ describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
99
99
 
100
100
  description = finder.source_description
101
101
 
102
- description.should eq 'errors'
102
+ expect(description).to eq 'errors'
103
103
  end
104
104
  end
105
105
 
@@ -119,7 +119,7 @@ describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
119
119
  def build_instance_validating(attribute, format, value)
120
120
  model_class = define_model(:example, attribute => :string) do
121
121
  attr_accessible attribute
122
- validates_format_of attribute, :with => format
122
+ validates_format_of attribute, with: format
123
123
  end
124
124
 
125
125
  model_class.new(attribute => value)
@@ -2,92 +2,92 @@ require 'spec_helper'
2
2
 
3
3
  describe Shoulda::Matchers::ActiveRecord::AcceptNestedAttributesForMatcher do
4
4
  it 'accepts an existing declaration' do
5
- accepting_children.should accept_nested_attributes_for(:children)
5
+ expect(accepting_children).to accept_nested_attributes_for(:children)
6
6
  end
7
7
 
8
8
  it 'rejects a missing declaration' do
9
9
  matcher = children_matcher
10
10
 
11
- matcher.matches?(rejecting_children).should be_false
11
+ expect(matcher.matches?(rejecting_children)).to eq false
12
12
 
13
- matcher.failure_message.
14
- should eq 'Expected Parent to accept nested attributes for children (is not declared)'
13
+ expect(matcher.failure_message).
14
+ to eq 'Expected Parent to accept nested attributes for children (is not declared)'
15
15
  end
16
16
 
17
17
  context 'allow_destroy' do
18
18
  it 'accepts a valid truthy value' do
19
- matching = accepting_children(:allow_destroy => true)
19
+ matching = accepting_children(allow_destroy: true)
20
20
 
21
- matching.should children_matcher.allow_destroy(true)
21
+ expect(matching).to children_matcher.allow_destroy(true)
22
22
  end
23
23
 
24
24
  it 'accepts a valid falsey value' do
25
- matching = accepting_children(:allow_destroy => false)
25
+ matching = accepting_children(allow_destroy: false)
26
26
 
27
- matching.should children_matcher.allow_destroy(false)
27
+ expect(matching).to children_matcher.allow_destroy(false)
28
28
  end
29
29
 
30
30
  it 'rejects an invalid truthy value' do
31
31
  matcher = children_matcher
32
- matching = accepting_children(:allow_destroy => true)
32
+ matching = accepting_children(allow_destroy: true)
33
33
 
34
- matcher.allow_destroy(false).matches?(matching).should be_false
35
- matcher.failure_message.should =~ /should not allow destroy/
34
+ expect(matcher.allow_destroy(false).matches?(matching)).to eq false
35
+ expect(matcher.failure_message).to match(/should not allow destroy/)
36
36
  end
37
37
 
38
38
  it 'rejects an invalid falsey value' do
39
39
  matcher = children_matcher
40
- matching = accepting_children(:allow_destroy => false)
40
+ matching = accepting_children(allow_destroy: false)
41
41
 
42
- matcher.allow_destroy(true).matches?(matching).should be_false
43
- matcher.failure_message.should =~ /should allow destroy/
42
+ expect(matcher.allow_destroy(true).matches?(matching)).to eq false
43
+ expect(matcher.failure_message).to match(/should allow destroy/)
44
44
  end
45
45
  end
46
46
 
47
47
  context 'limit' do
48
48
  it 'accepts a correct value' do
49
- accepting_children(:limit => 3).should children_matcher.limit(3)
49
+ expect(accepting_children(limit: 3)).to children_matcher.limit(3)
50
50
  end
51
51
 
52
52
  it 'rejects a false value' do
53
53
  matcher = children_matcher
54
- rejecting = accepting_children(:limit => 3)
54
+ rejecting = accepting_children(limit: 3)
55
55
 
56
- matcher.limit(2).matches?(rejecting).should be_false
57
- matcher.failure_message.should =~ /limit should be 2, got 3/
56
+ expect(matcher.limit(2).matches?(rejecting)).to eq false
57
+ expect(matcher.failure_message).to match(/limit should be 2, got 3/)
58
58
  end
59
59
  end
60
60
 
61
61
  context 'update_only' do
62
62
  it 'accepts a valid truthy value' do
63
- accepting_children(:update_only => true).
64
- should children_matcher.update_only(true)
63
+ expect(accepting_children(update_only: true)).
64
+ to children_matcher.update_only(true)
65
65
  end
66
66
 
67
67
  it 'accepts a valid falsey value' do
68
- accepting_children(:update_only => false).
69
- should children_matcher.update_only(false)
68
+ expect(accepting_children(update_only: false)).
69
+ to children_matcher.update_only(false)
70
70
  end
71
71
 
72
72
  it 'rejects an invalid truthy value' do
73
73
  matcher = children_matcher.update_only(false)
74
- rejecting = accepting_children(:update_only => true)
74
+ rejecting = accepting_children(update_only: true)
75
75
 
76
- matcher.matches?(rejecting).should be_false
77
- matcher.failure_message.should =~ /should not be update only/
76
+ expect(matcher.matches?(rejecting)).to eq false
77
+ expect(matcher.failure_message).to match(/should not be update only/)
78
78
  end
79
79
 
80
80
  it 'rejects an invalid falsey value' do
81
81
  matcher = children_matcher.update_only(true)
82
- rejecting = accepting_children(:update_only => false)
82
+ rejecting = accepting_children(update_only: false)
83
83
 
84
- matcher.matches?(rejecting).should be_false
85
- matcher.failure_message.should =~ /should be update only/
84
+ expect(matcher.matches?(rejecting)).to eq false
85
+ expect(matcher.failure_message).to match(/should be update only/)
86
86
  end
87
87
  end
88
88
 
89
89
  def accepting_children(options = {})
90
- define_model :child, :parent_id => :integer
90
+ define_model :child, parent_id: :integer
91
91
  define_model :parent do
92
92
  has_many :children
93
93
  accepts_nested_attributes_for :children, options
@@ -99,7 +99,7 @@ describe Shoulda::Matchers::ActiveRecord::AcceptNestedAttributesForMatcher do
99
99
  end
100
100
 
101
101
  def rejecting_children
102
- define_model :child, :parent_id => :integer
102
+ define_model :child, parent_id: :integer
103
103
  define_model :parent do
104
104
  has_many :children
105
105
  end.new
@@ -3,128 +3,178 @@ require 'spec_helper'
3
3
  describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
4
4
  context 'belong_to' do
5
5
  it 'accepts a good association with the default foreign key' do
6
- belonging_to_parent.should belong_to(:parent)
6
+ expect(belonging_to_parent).to belong_to(:parent)
7
7
  end
8
8
 
9
9
  it 'rejects a nonexistent association' do
10
- define_model(:child).new.should_not belong_to(:parent)
10
+ expect(define_model(:child).new).not_to belong_to(:parent)
11
11
  end
12
12
 
13
13
  it 'rejects an association of the wrong type' do
14
- define_model :parent, :child_id => :integer
15
- define_model(:child) { has_one :parent }.new.should_not belong_to(:parent)
14
+ define_model :parent, child_id: :integer
15
+ expect(define_model(:child) { has_one :parent }.new).not_to belong_to(:parent)
16
16
  end
17
17
 
18
18
  it 'rejects an association that has a nonexistent foreign key' do
19
19
  define_model :parent
20
- define_model(:child) { belongs_to :parent }.new.should_not belong_to(:parent)
20
+ expect(define_model(:child) { belongs_to :parent }.new).not_to belong_to(:parent)
21
21
  end
22
22
 
23
23
  it 'accepts an association with an existing custom foreign key' do
24
24
  define_model :parent
25
- define_model :child, :guardian_id => :integer do
26
- belongs_to :parent, :foreign_key => 'guardian_id'
25
+ define_model :child, guardian_id: :integer do
26
+ belongs_to :parent, foreign_key: 'guardian_id'
27
27
  end
28
28
 
29
- Child.new.should belong_to(:parent)
29
+ expect(Child.new).to belong_to(:parent)
30
30
  end
31
31
 
32
32
  it 'accepts a polymorphic association' do
33
- define_model :child, :parent_type => :string, :parent_id => :integer do
34
- belongs_to :parent, :polymorphic => true
33
+ define_model :child, parent_type: :string, parent_id: :integer do
34
+ belongs_to :parent, polymorphic: true
35
35
  end
36
36
 
37
- Child.new.should belong_to(:parent)
37
+ expect(Child.new).to belong_to(:parent)
38
38
  end
39
39
 
40
40
  it 'accepts an association with a valid :dependent option' do
41
- belonging_to_parent(:dependent => :destroy).
42
- should belong_to(:parent).dependent(:destroy)
41
+ expect(belonging_to_parent(dependent: :destroy)).
42
+ to belong_to(:parent).dependent(:destroy)
43
43
  end
44
44
 
45
45
  it 'rejects an association with a bad :dependent option' do
46
- belonging_to_parent.should_not belong_to(:parent).dependent(:destroy)
46
+ expect(belonging_to_parent).not_to belong_to(:parent).dependent(:destroy)
47
47
  end
48
48
 
49
49
  it 'accepts an association with a valid :counter_cache option' do
50
- belonging_to_parent(:counter_cache => :attribute_count).
51
- should belong_to(:parent).counter_cache(:attribute_count)
50
+ expect(belonging_to_parent(counter_cache: :attribute_count)).
51
+ to belong_to(:parent).counter_cache(:attribute_count)
52
52
  end
53
53
 
54
54
  it 'defaults :counter_cache to true' do
55
- belonging_to_parent(:counter_cache => true).
56
- should belong_to(:parent).counter_cache
55
+ expect(belonging_to_parent(counter_cache: true)).
56
+ to belong_to(:parent).counter_cache
57
57
  end
58
58
 
59
59
  it 'rejects an association with a bad :counter_cache option' do
60
- belonging_to_parent(:counter_cache => :attribute_count).
61
- should_not belong_to(:parent).counter_cache(true)
60
+ expect(belonging_to_parent(counter_cache: :attribute_count)).
61
+ not_to belong_to(:parent).counter_cache(true)
62
62
  end
63
63
 
64
64
  it 'rejects an association that has no :counter_cache option' do
65
- belonging_to_parent.should_not belong_to(:parent).counter_cache
65
+ expect(belonging_to_parent).not_to belong_to(:parent).counter_cache
66
+ end
67
+
68
+ it 'accepts an association with a valid :inverse_of option' do
69
+ expect(belonging_to_parent(inverse_of: :children))
70
+ .to belong_to(:parent).inverse_of(:children)
71
+ end
72
+
73
+ it 'rejects an association with a bad :inverse_of option' do
74
+ expect(belonging_to_parent(inverse_of: :other_children))
75
+ .not_to belong_to(:parent).inverse_of(:children)
76
+ end
77
+
78
+ it 'rejects an association that has no :inverse_of option' do
79
+ expect(belonging_to_parent)
80
+ .not_to belong_to(:parent).inverse_of(:children)
66
81
  end
67
82
 
68
83
  it 'accepts an association with a valid :conditions option' do
69
- define_model :parent, :adopter => :boolean
70
- define_model(:child, :parent_id => :integer).tap do |model|
71
- define_association_with_conditions(model, :belongs_to, :parent, :adopter => true)
84
+ define_model :parent, adopter: :boolean
85
+ define_model(:child, parent_id: :integer).tap do |model|
86
+ define_association_with_conditions(model, :belongs_to, :parent, adopter: true)
72
87
  end
73
88
 
74
- Child.new.should belong_to(:parent).conditions(:adopter => true)
89
+ expect(Child.new).to belong_to(:parent).conditions(adopter: true)
75
90
  end
76
91
 
77
92
  it 'rejects an association with a bad :conditions option' do
78
- define_model :parent, :adopter => :boolean
79
- define_model :child, :parent_id => :integer do
93
+ define_model :parent, adopter: :boolean
94
+ define_model :child, parent_id: :integer do
80
95
  belongs_to :parent
81
96
  end
82
97
 
83
- Child.new.should_not belong_to(:parent).conditions(:adopter => true)
98
+ expect(Child.new).not_to belong_to(:parent).conditions(adopter: true)
84
99
  end
85
100
 
86
101
  it 'accepts an association without a :class_name option' do
87
- belonging_to_parent.should belong_to(:parent).class_name('Parent')
102
+ expect(belonging_to_parent).to belong_to(:parent).class_name('Parent')
88
103
  end
89
104
 
90
105
  it 'accepts an association with a valid :class_name option' do
91
106
  define_model :tree_parent
92
- define_model :child, :parent_id => :integer do
93
- belongs_to :parent, :class_name => 'TreeParent'
107
+ define_model :child, parent_id: :integer do
108
+ belongs_to :parent, class_name: 'TreeParent'
94
109
  end
95
110
 
96
- Child.new.should belong_to(:parent).class_name('TreeParent')
111
+ expect(Child.new).to belong_to(:parent).class_name('TreeParent')
97
112
  end
98
113
 
99
114
  it 'rejects an association with a bad :class_name option' do
100
- belonging_to_parent.should_not belong_to(:parent).class_name('TreeChild')
115
+ expect(belonging_to_parent).not_to belong_to(:parent).class_name('TreeChild')
116
+ end
117
+
118
+ it 'rejects an association with non-existent implicit class name' do
119
+ expect(belonging_to_non_existent_class(:child, :parent)).not_to belong_to(:parent)
120
+ end
121
+
122
+ it 'rejects an association with non-existent explicit class name' do
123
+ expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent')).not_to belong_to(:parent)
124
+ end
125
+
126
+ it 'adds error message when rejecting an association with non-existent class' do
127
+ message = 'Expected Child to have a belongs_to association called parent (Parent2 does not exist)'
128
+ expect {
129
+ expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent2')).to belong_to(:parent)
130
+ }.to fail_with_message(message)
131
+ end
132
+
133
+ it 'accepts an association with a matching :autosave option' do
134
+ define_model :parent, adopter: :boolean
135
+ define_model :child, parent_id: :integer do
136
+ belongs_to :parent, autosave: true
137
+ end
138
+ expect(Child.new).to belong_to(:parent).autosave(true)
139
+ end
140
+
141
+ it 'rejects an association with a non-matching :autosave option with the correct message' do
142
+ define_model :parent, adopter: :boolean
143
+ define_model :child, parent_id: :integer do
144
+ belongs_to :parent, autosave: false
145
+ end
146
+
147
+ message = 'Expected Child to have a belongs_to association called parent (parent should have autosave set to true)'
148
+ expect {
149
+ expect(Child.new).to belong_to(:parent).autosave(true)
150
+ }.to fail_with_message(message)
101
151
  end
102
152
 
103
153
  context 'an association with a :validate option' do
104
154
  [false, true].each do |validate_value|
105
- context "when the model has :validate => #{validate_value}" do
155
+ context "when the model has validate: #{validate_value}" do
106
156
  it 'accepts a matching validate option' do
107
- belonging_to_parent(:validate => validate_value).
108
- should belong_to(:parent).validate(validate_value)
157
+ expect(belonging_to_parent(validate: validate_value)).
158
+ to belong_to(:parent).validate(validate_value)
109
159
  end
110
160
 
111
161
  it 'rejects a non-matching validate option' do
112
- belonging_to_parent(:validate => validate_value).
113
- should_not belong_to(:parent).validate(!validate_value)
162
+ expect(belonging_to_parent(validate: validate_value)).
163
+ not_to belong_to(:parent).validate(!validate_value)
114
164
  end
115
165
 
116
166
  it 'defaults to validate(true)' do
117
167
  if validate_value
118
- belonging_to_parent(:validate => validate_value).
119
- should belong_to(:parent).validate
168
+ expect(belonging_to_parent(validate: validate_value)).
169
+ to belong_to(:parent).validate
120
170
  else
121
- belonging_to_parent(:validate => validate_value).
122
- should_not belong_to(:parent).validate
171
+ expect(belonging_to_parent(validate: validate_value)).
172
+ not_to belong_to(:parent).validate
123
173
  end
124
174
  end
125
175
 
126
176
  it 'will not break matcher when validate option is unspecified' do
127
- belonging_to_parent(:validate => validate_value).should belong_to(:parent)
177
+ expect(belonging_to_parent(validate: validate_value)).to belong_to(:parent)
128
178
  end
129
179
  end
130
180
  end
@@ -132,43 +182,43 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
132
182
 
133
183
  context 'an association without a :validate option' do
134
184
  it 'accepts validate(false)' do
135
- belonging_to_parent.should belong_to(:parent).validate(false)
185
+ expect(belonging_to_parent).to belong_to(:parent).validate(false)
136
186
  end
137
187
 
138
188
  it 'rejects validate(true)' do
139
- belonging_to_parent.should_not belong_to(:parent).validate(true)
189
+ expect(belonging_to_parent).not_to belong_to(:parent).validate(true)
140
190
  end
141
191
 
142
192
  it 'rejects validate()' do
143
- belonging_to_parent.should_not belong_to(:parent).validate
193
+ expect(belonging_to_parent).not_to belong_to(:parent).validate
144
194
  end
145
195
  end
146
196
 
147
197
  context 'an association with a :touch option' do
148
198
  [false, true].each do |touch_value|
149
- context "when the model has :touch => #{touch_value}" do
199
+ context "when the model has touch: #{touch_value}" do
150
200
  it 'accepts a matching touch option' do
151
- belonging_to_parent(:touch => touch_value).
152
- should belong_to(:parent).touch(touch_value)
201
+ expect(belonging_to_parent(touch: touch_value)).
202
+ to belong_to(:parent).touch(touch_value)
153
203
  end
154
204
 
155
205
  it 'rejects a non-matching touch option' do
156
- belonging_to_parent(:touch => touch_value).
157
- should_not belong_to(:parent).touch(!touch_value)
206
+ expect(belonging_to_parent(touch: touch_value)).
207
+ not_to belong_to(:parent).touch(!touch_value)
158
208
  end
159
209
 
160
210
  it 'defaults to touch(true)' do
161
211
  if touch_value
162
- belonging_to_parent(:touch => touch_value).
163
- should belong_to(:parent).touch
212
+ expect(belonging_to_parent(touch: touch_value)).
213
+ to belong_to(:parent).touch
164
214
  else
165
- belonging_to_parent(:touch => touch_value).
166
- should_not belong_to(:parent).touch
215
+ expect(belonging_to_parent(touch: touch_value)).
216
+ not_to belong_to(:parent).touch
167
217
  end
168
218
  end
169
219
 
170
220
  it 'will not break matcher when touch option is unspecified' do
171
- belonging_to_parent(:touch => touch_value).should belong_to(:parent)
221
+ expect(belonging_to_parent(touch: touch_value)).to belong_to(:parent)
172
222
  end
173
223
  end
174
224
  end
@@ -176,51 +226,57 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
176
226
 
177
227
  context 'an association without a :touch option' do
178
228
  it 'accepts touch(false)' do
179
- belonging_to_parent.should belong_to(:parent).touch(false)
229
+ expect(belonging_to_parent).to belong_to(:parent).touch(false)
180
230
  end
181
231
 
182
232
  it 'rejects touch(true)' do
183
- belonging_to_parent.should_not belong_to(:parent).touch(true)
233
+ expect(belonging_to_parent).not_to belong_to(:parent).touch(true)
184
234
  end
185
235
 
186
236
  it 'rejects touch()' do
187
- belonging_to_parent.should_not belong_to(:parent).touch
237
+ expect(belonging_to_parent).not_to belong_to(:parent).touch
188
238
  end
189
239
  end
190
240
 
191
241
  def belonging_to_parent(options = {})
192
242
  define_model :parent
193
- define_model :child, :parent_id => :integer do
243
+ define_model :child, parent_id: :integer do
194
244
  belongs_to :parent, options
195
245
  end.new
196
246
  end
247
+
248
+ def belonging_to_non_existent_class(model_name, assoc_name, options = {})
249
+ define_model model_name, "#{assoc_name}_id" => :integer do
250
+ belongs_to assoc_name, options
251
+ end.new
252
+ end
197
253
  end
198
254
 
199
255
  context 'have_many' do
200
256
  it 'accepts a valid association without any options' do
201
- having_many_children.should have_many(:children)
257
+ expect(having_many_children).to have_many(:children)
202
258
  end
203
259
 
204
260
  it 'accepts a valid association with a :through option' do
205
261
  define_model :child
206
- define_model :conception, :child_id => :integer,
207
- :parent_id => :integer do
262
+ define_model :conception, child_id: :integer,
263
+ parent_id: :integer do
208
264
  belongs_to :child
209
265
  end
210
266
  define_model :parent do
211
267
  has_many :conceptions
212
- has_many :children, :through => :conceptions
268
+ has_many :children, through: :conceptions
213
269
  end
214
- Parent.new.should have_many(:children)
270
+ expect(Parent.new).to have_many(:children)
215
271
  end
216
272
 
217
273
  it 'accepts a valid association with an :as option' do
218
- define_model :child, :guardian_type => :string, :guardian_id => :integer
274
+ define_model :child, guardian_type: :string, guardian_id: :integer
219
275
  define_model :parent do
220
- has_many :children, :as => :guardian
276
+ has_many :children, as: :guardian
221
277
  end
222
278
 
223
- Parent.new.should have_many(:children)
279
+ expect(Parent.new).to have_many(:children)
224
280
  end
225
281
 
226
282
  it 'rejects an association that has a nonexistent foreign key' do
@@ -229,164 +285,199 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
229
285
  has_many :children
230
286
  end
231
287
 
232
- Parent.new.should_not have_many(:children)
288
+ expect(Parent.new).not_to have_many(:children)
233
289
  end
234
290
 
235
291
  it 'rejects an association with a bad :as option' do
236
- define_model :child, :caretaker_type => :string,
237
- :caretaker_id => :integer
292
+ define_model :child, caretaker_type: :string,
293
+ caretaker_id: :integer
238
294
  define_model :parent do
239
- has_many :children, :as => :guardian
295
+ has_many :children, as: :guardian
240
296
  end
241
297
 
242
- Parent.new.should_not have_many(:children)
298
+ expect(Parent.new).not_to have_many(:children)
243
299
  end
244
300
 
245
301
  it 'rejects an association that has a bad :through option' do
246
302
  matcher = have_many(:children).through(:conceptions)
247
303
 
248
- matcher.matches?(having_many_children).should be_false
304
+ expect(matcher.matches?(having_many_children)).to eq false
249
305
 
250
- matcher.failure_message.should =~ /does not have any relationship to conceptions/
306
+ expect(matcher.failure_message).to match(/does not have any relationship to conceptions/)
251
307
  end
252
308
 
253
309
  it 'rejects an association that has the wrong :through option' do
254
310
  define_model :child
255
311
 
256
- define_model :conception, :child_id => :integer,
257
- :parent_id => :integer do
312
+ define_model :conception, child_id: :integer,
313
+ parent_id: :integer do
258
314
  belongs_to :child
259
315
  end
260
316
 
261
317
  define_model :parent do
262
318
  has_many :conceptions
263
319
  has_many :relationships
264
- has_many :children, :through => :conceptions
320
+ has_many :children, through: :conceptions
265
321
  end
266
322
 
267
323
  matcher = have_many(:children).through(:relationships)
268
- matcher.matches?(Parent.new).should be_false
269
- matcher.failure_message.should =~ /through relationships, but got it through conceptions/
324
+ expect(matcher.matches?(Parent.new)).to eq false
325
+ expect(matcher.failure_message).to match(/through relationships, but got it through conceptions/)
270
326
  end
271
327
 
272
328
  it 'accepts an association with a valid :dependent option' do
273
- having_many_children(:dependent => :destroy).
274
- should have_many(:children).dependent(:destroy)
329
+ expect(having_many_children(dependent: :destroy)).
330
+ to have_many(:children).dependent(:destroy)
275
331
  end
276
332
 
277
333
  it 'rejects an association with a bad :dependent option' do
278
334
  matcher = have_many(:children).dependent(:destroy)
279
335
 
280
- having_many_children.should_not matcher
336
+ expect(having_many_children).not_to matcher
281
337
 
282
- matcher.failure_message.should =~ /children should have destroy dependency/
338
+ expect(matcher.failure_message).to match(/children should have destroy dependency/)
283
339
  end
284
340
 
285
341
  it 'accepts an association with a valid :source option' do
286
- having_many_children(:source => :user).
287
- should have_many(:children).source(:user)
342
+ expect(having_many_children(source: :user)).
343
+ to have_many(:children).source(:user)
288
344
  end
289
345
 
290
346
  it 'rejects an association with a bad :source option' do
291
347
  matcher = have_many(:children).source(:user)
292
348
 
293
- having_many_children.should_not matcher
349
+ expect(having_many_children).not_to matcher
294
350
 
295
- matcher.failure_message.should =~ /children should have user as source option/
351
+ expect(matcher.failure_message).to match(/children should have user as source option/)
296
352
  end
297
353
 
298
354
  it 'accepts an association with a valid :order option' do
299
- having_many_children(:order => :id).
300
- should have_many(:children).order(:id)
355
+ expect(having_many_children(order: :id)).
356
+ to have_many(:children).order(:id)
301
357
  end
302
358
 
303
359
  it 'rejects an association with a bad :order option' do
304
360
  matcher = have_many(:children).order(:id)
305
361
 
306
- having_many_children.should_not matcher
362
+ expect(having_many_children).not_to matcher
307
363
 
308
- matcher.failure_message.should =~ /children should be ordered by id/
364
+ expect(matcher.failure_message).to match(/children should be ordered by id/)
309
365
  end
310
366
 
311
367
  it 'accepts an association with a valid :conditions option' do
312
- define_model :child, :parent_id => :integer, :adopted => :boolean
368
+ define_model :child, parent_id: :integer, adopted: :boolean
313
369
  define_model(:parent).tap do |model|
314
- define_association_with_conditions(model, :has_many, :children, :adopted => true)
370
+ define_association_with_conditions(model, :has_many, :children, adopted: true)
315
371
  end
316
372
 
317
- Parent.new.should have_many(:children).conditions(:adopted => true)
373
+ expect(Parent.new).to have_many(:children).conditions(adopted: true)
318
374
  end
319
375
 
320
376
  it 'rejects an association with a bad :conditions option' do
321
- define_model :child, :parent_id => :integer, :adopted => :boolean
377
+ define_model :child, parent_id: :integer, adopted: :boolean
322
378
  define_model :parent do
323
379
  has_many :children
324
380
  end
325
381
 
326
- Parent.new.should_not have_many(:children).conditions(:adopted => true)
382
+ expect(Parent.new).not_to have_many(:children).conditions(adopted: true)
327
383
  end
328
384
 
329
385
  it 'accepts an association without a :class_name option' do
330
- having_many_children.should have_many(:children).class_name('Child')
386
+ expect(having_many_children).to have_many(:children).class_name('Child')
331
387
  end
332
388
 
333
389
  it 'accepts an association with a valid :class_name option' do
334
- define_model :node, :parent_id => :integer
390
+ define_model :node, parent_id: :integer
335
391
  define_model :parent do
336
- has_many :children, :class_name => 'Node'
392
+ has_many :children, class_name: 'Node'
337
393
  end
338
394
 
339
- Parent.new.should have_many(:children).class_name('Node')
395
+ expect(Parent.new).to have_many(:children).class_name('Node')
340
396
  end
341
397
 
342
398
  it 'rejects an association with a bad :class_name option' do
343
- having_many_children.should_not have_many(:children).class_name('Node')
399
+ expect(having_many_children).not_to have_many(:children).class_name('Node')
400
+ end
401
+
402
+ it 'rejects an association with non-existent implicit class name' do
403
+ expect(having_many_non_existent_class(:parent, :children)).not_to have_many(:children)
404
+ end
405
+
406
+ it 'rejects an association with non-existent explicit class name' do
407
+ expect(having_many_non_existent_class(:parent, :children, class_name: 'Child')).not_to have_many(:children)
408
+ end
409
+
410
+ it 'adds error message when rejecting an association with non-existent class' do
411
+ message = 'Expected Parent to have a has_many association called children (Child2 does not exist)'
412
+ expect {
413
+ expect(having_many_non_existent_class(:parent, :children, class_name: 'Child2')).to have_many(:children)
414
+ }.to fail_with_message(message)
415
+ end
416
+
417
+ it 'accepts an association with a matching :autosave option' do
418
+ define_model :child, parent_id: :integer
419
+ define_model :parent do
420
+ has_many :children, autosave: true
421
+ end
422
+ expect(Parent.new).to have_many(:children).autosave(true)
423
+ end
424
+
425
+ it 'rejects an association with a non-matching :autosave option with the correct message' do
426
+ define_model :child, parent_id: :integer
427
+ define_model :parent do
428
+ has_many :children, autosave: false
429
+ end
430
+
431
+ message = 'Expected Parent to have a has_many association called children (children should have autosave set to true)'
432
+ expect {
433
+ expect(Parent.new).to have_many(:children).autosave(true)
434
+ }.to fail_with_message(message)
344
435
  end
345
436
 
346
437
  context 'validate' do
347
438
  it 'accepts when the :validate option matches' do
348
- having_many_children(:validate => false).should have_many(:children).validate(false)
439
+ expect(having_many_children(validate: false)).to have_many(:children).validate(false)
349
440
  end
350
441
 
351
442
  it 'rejects when the :validate option does not match' do
352
- having_many_children(:validate => true).should_not have_many(:children).validate(false)
443
+ expect(having_many_children(validate: true)).not_to have_many(:children).validate(false)
353
444
  end
354
445
 
355
446
  it 'assumes validate() means validate(true)' do
356
- having_many_children(:validate => false).should_not have_many(:children).validate
447
+ expect(having_many_children(validate: false)).not_to have_many(:children).validate
357
448
  end
358
449
 
359
450
  it 'matches validate(false) to having no validate option specified' do
360
- having_many_children.should have_many(:children).validate(false)
451
+ expect(having_many_children).to have_many(:children).validate(false)
361
452
  end
362
453
  end
363
454
 
364
455
  it 'accepts an association with a nonstandard reverse foreign key, using :inverse_of' do
365
- define_model :child, :ancestor_id => :integer do
366
- belongs_to :ancestor, :inverse_of => :children, :class_name => :Parent
456
+ define_model :child, ancestor_id: :integer do
457
+ belongs_to :ancestor, inverse_of: :children, class_name: :Parent
367
458
  end
368
459
 
369
460
  define_model :parent do
370
- has_many :children, :inverse_of => :ancestor
461
+ has_many :children, inverse_of: :ancestor
371
462
  end
372
463
 
373
- Parent.new.should have_many(:children)
464
+ expect(Parent.new).to have_many(:children)
374
465
  end
375
466
 
376
467
  it 'rejects an association with a nonstandard reverse foreign key, if :inverse_of is not correct' do
377
- define_model :child, :mother_id => :integer do
378
- belongs_to :mother, :inverse_of => :children, :class_name => :Parent
468
+ define_model :child, mother_id: :integer do
469
+ belongs_to :mother, inverse_of: :children, class_name: :Parent
379
470
  end
380
471
 
381
472
  define_model :parent do
382
- has_many :children, :inverse_of => :ancestor
473
+ has_many :children, inverse_of: :ancestor
383
474
  end
384
475
 
385
- Parent.new.should_not have_many(:children)
476
+ expect(Parent.new).not_to have_many(:children)
386
477
  end
387
478
 
388
479
  def having_many_children(options = {})
389
- define_model :child, :parent_id => :integer
480
+ define_model :child, parent_id: :integer
390
481
  define_model(:parent).tap do |model|
391
482
  if options.key?(:order)
392
483
  order = options.delete(:order)
@@ -396,21 +487,27 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
396
487
  end
397
488
  end.new
398
489
  end
490
+
491
+ def having_many_non_existent_class(model_name, assoc_name, options = {})
492
+ define_model model_name do
493
+ has_many assoc_name, options
494
+ end.new
495
+ end
399
496
  end
400
497
 
401
498
  context 'have_one' do
402
499
  it 'accepts a valid association without any options' do
403
- having_one_detail.should have_one(:detail)
500
+ expect(having_one_detail).to have_one(:detail)
404
501
  end
405
502
 
406
503
  it 'accepts a valid association with an :as option' do
407
- define_model :detail, :detailable_id => :integer,
408
- :detailable_type => :string
504
+ define_model :detail, detailable_id: :integer,
505
+ detailable_type: :string
409
506
  define_model :person do
410
- has_one :detail, :as => :detailable
507
+ has_one :detail, as: :detailable
411
508
  end
412
509
 
413
- Person.new.should have_one(:detail)
510
+ expect(Person.new).to have_one(:detail)
414
511
  end
415
512
 
416
513
  it 'rejects an association that has a nonexistent foreign key' do
@@ -419,85 +516,120 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
419
516
  has_one :detail
420
517
  end
421
518
 
422
- Person.new.should_not have_one(:detail)
519
+ expect(Person.new).not_to have_one(:detail)
423
520
  end
424
521
 
425
522
  it 'accepts an association with an existing custom foreign key' do
426
- define_model :detail, :detailed_person_id => :integer
523
+ define_model :detail, detailed_person_id: :integer
427
524
  define_model :person do
428
- has_one :detail, :foreign_key => :detailed_person_id
525
+ has_one :detail, foreign_key: :detailed_person_id
429
526
  end
430
- Person.new.should have_one(:detail).with_foreign_key(:detailed_person_id)
527
+ expect(Person.new).to have_one(:detail).with_foreign_key(:detailed_person_id)
431
528
  end
432
529
 
433
530
  it 'rejects an association with a bad :as option' do
434
- define_model :detail, :detailable_id => :integer,
435
- :detailable_type => :string
531
+ define_model :detail, detailable_id: :integer,
532
+ detailable_type: :string
436
533
  define_model :person do
437
- has_one :detail, :as => :describable
534
+ has_one :detail, as: :describable
438
535
  end
439
536
 
440
- Person.new.should_not have_one(:detail)
537
+ expect(Person.new).not_to have_one(:detail)
441
538
  end
442
539
 
443
540
  it 'accepts an association with a valid :dependent option' do
444
- having_one_detail(:dependent => :destroy).
445
- should have_one(:detail).dependent(:destroy)
541
+ expect(having_one_detail(dependent: :destroy)).
542
+ to have_one(:detail).dependent(:destroy)
446
543
  end
447
544
 
448
545
  it 'rejects an association with a bad :dependent option' do
449
546
  matcher = have_one(:detail).dependent(:destroy)
450
547
 
451
- having_one_detail.should_not matcher
548
+ expect(having_one_detail).not_to matcher
452
549
 
453
- matcher.failure_message.should =~ /detail should have destroy dependency/
550
+ expect(matcher.failure_message).to match(/detail should have destroy dependency/)
454
551
  end
455
552
 
456
553
  it 'accepts an association with a valid :order option' do
457
- having_one_detail(:order => :id).should have_one(:detail).order(:id)
554
+ expect(having_one_detail(order: :id)).to have_one(:detail).order(:id)
458
555
  end
459
556
 
460
557
  it 'rejects an association with a bad :order option' do
461
558
  matcher = have_one(:detail).order(:id)
462
559
 
463
- having_one_detail.should_not matcher
560
+ expect(having_one_detail).not_to matcher
464
561
 
465
- matcher.failure_message.should =~ /detail should be ordered by id/
562
+ expect(matcher.failure_message).to match(/detail should be ordered by id/)
466
563
  end
467
564
 
468
565
  it 'accepts an association with a valid :conditions option' do
469
- define_model :detail, :person_id => :integer, :disabled => :boolean
566
+ define_model :detail, person_id: :integer, disabled: :boolean
470
567
  define_model(:person).tap do |model|
471
- define_association_with_conditions(model, :has_one, :detail, :disabled => true)
568
+ define_association_with_conditions(model, :has_one, :detail, disabled: true)
472
569
  end
473
570
 
474
- Person.new.should have_one(:detail).conditions(:disabled => true)
571
+ expect(Person.new).to have_one(:detail).conditions(disabled: true)
475
572
  end
476
573
 
477
574
  it 'rejects an association with a bad :conditions option' do
478
- define_model :detail, :person_id => :integer, :disabled => :boolean
575
+ define_model :detail, person_id: :integer, disabled: :boolean
479
576
  define_model :person do
480
577
  has_one :detail
481
578
  end
482
579
 
483
- Person.new.should_not have_one(:detail).conditions(:disabled => true)
580
+ expect(Person.new).not_to have_one(:detail).conditions(disabled: true)
484
581
  end
485
582
 
486
583
  it 'accepts an association without a :class_name option' do
487
- having_one_detail.should have_one(:detail).class_name('Detail')
584
+ expect(having_one_detail).to have_one(:detail).class_name('Detail')
585
+ end
586
+
587
+ it 'accepts an association with a matching :autosave option' do
588
+ define_model :detail, person_id: :integer, disabled: :boolean
589
+ define_model :person do
590
+ has_one :detail, autosave: true
591
+ end
592
+ expect(Person.new).to have_one(:detail).autosave(true)
593
+ end
594
+
595
+ it 'rejects an association with a non-matching :autosave option with the correct message' do
596
+ define_model :detail, person_id: :integer, disabled: :boolean
597
+ define_model :person do
598
+ has_one :detail, autosave: false
599
+ end
600
+
601
+ message = 'Expected Person to have a has_one association called detail (detail should have autosave set to true)'
602
+ expect {
603
+ expect(Person.new).to have_one(:detail).autosave(true)
604
+ }.to fail_with_message(message)
488
605
  end
489
606
 
490
607
  it 'accepts an association with a valid :class_name option' do
491
- define_model :person_detail, :person_id => :integer
608
+ define_model :person_detail, person_id: :integer
492
609
  define_model :person do
493
- has_one :detail, :class_name => 'PersonDetail'
610
+ has_one :detail, class_name: 'PersonDetail'
494
611
  end
495
612
 
496
- Person.new.should have_one(:detail).class_name('PersonDetail')
613
+ expect(Person.new).to have_one(:detail).class_name('PersonDetail')
497
614
  end
498
615
 
499
616
  it 'rejects an association with a bad :class_name option' do
500
- having_one_detail.should_not have_one(:detail).class_name('NotSet')
617
+ expect(having_one_detail).not_to have_one(:detail).class_name('NotSet')
618
+ end
619
+
620
+ it 'rejects an association with non-existent implicit class name' do
621
+ expect(having_one_non_existent(:pserson, :detail)).not_to have_one(:detail)
622
+ end
623
+
624
+ it 'rejects an association with non-existent explicit class name' do
625
+ expect(having_one_non_existent(:person, :detail, class_name: 'Detail')).not_to have_one(:detail)
626
+ end
627
+
628
+ it 'adds error message when rejecting an association with non-existent class' do
629
+ message = 'Expected Person to have a has_one association called detail (Detail2 does not exist)'
630
+ expect {
631
+ expect(having_one_non_existent(:person, :detail, class_name: 'Detail2')).to have_one(:detail)
632
+ }.to fail_with_message(message)
501
633
  end
502
634
 
503
635
  it 'accepts an association with a through' do
@@ -509,39 +641,39 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
509
641
 
510
642
  define_model :person do
511
643
  has_one :account
512
- has_one :detail, :through => :account
644
+ has_one :detail, through: :account
513
645
  end
514
646
 
515
- Person.new.should have_one(:detail).through(:account)
647
+ expect(Person.new).to have_one(:detail).through(:account)
516
648
  end
517
649
 
518
650
  it 'rejects an association with a bad through' do
519
- having_one_detail.should_not have_one(:detail).through(:account)
651
+ expect(having_one_detail).not_to have_one(:detail).through(:account)
520
652
  end
521
653
 
522
654
  context 'validate' do
523
655
  it 'accepts when the :validate option matches' do
524
- having_one_detail(:validate => false).
525
- should have_one(:detail).validate(false)
656
+ expect(having_one_detail(validate: false)).
657
+ to have_one(:detail).validate(false)
526
658
  end
527
659
 
528
660
  it 'rejects when the :validate option does not match' do
529
- having_one_detail(:validate => true).
530
- should_not have_one(:detail).validate(false)
661
+ expect(having_one_detail(validate: true)).
662
+ not_to have_one(:detail).validate(false)
531
663
  end
532
664
 
533
665
  it 'assumes validate() means validate(true)' do
534
- having_one_detail(:validate => false).
535
- should_not have_one(:detail).validate
666
+ expect(having_one_detail(validate: false)).
667
+ not_to have_one(:detail).validate
536
668
  end
537
669
 
538
670
  it 'matches validate(false) to having no validate option specified' do
539
- having_one_detail.should have_one(:detail).validate(false)
671
+ expect(having_one_detail).to have_one(:detail).validate(false)
540
672
  end
541
673
  end
542
674
 
543
675
  def having_one_detail(options = {})
544
- define_model :detail, :person_id => :integer
676
+ define_model :detail, person_id: :integer
545
677
  define_model(:person).tap do |model|
546
678
  if options.key?(:order)
547
679
  order = options.delete(:order)
@@ -551,21 +683,27 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
551
683
  end
552
684
  end.new
553
685
  end
686
+
687
+ def having_one_non_existent(model_name, assoc_name, options = {})
688
+ define_model model_name do
689
+ has_one assoc_name, options
690
+ end.new
691
+ end
554
692
  end
555
693
 
556
694
  context 'have_and_belong_to_many' do
557
695
  it 'accepts a valid association' do
558
- having_and_belonging_to_many_relatives.
559
- should have_and_belong_to_many(:relatives)
696
+ expect(having_and_belonging_to_many_relatives).
697
+ to have_and_belong_to_many(:relatives)
560
698
  end
561
699
 
562
700
  it 'rejects a nonexistent association' do
563
701
  define_model :relative
564
702
  define_model :person
565
- define_model :people_relative, :id => false, :person_id => :integer,
566
- :relative_id => :integer
703
+ define_model :people_relative, id: false, person_id: :integer,
704
+ relative_id: :integer
567
705
 
568
- Person.new.should_not have_and_belong_to_many(:relatives)
706
+ expect(Person.new).not_to have_and_belong_to_many(:relatives)
569
707
  end
570
708
 
571
709
  it 'rejects an association with a nonexistent join table' do
@@ -574,92 +712,140 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
574
712
  has_and_belongs_to_many :relatives
575
713
  end
576
714
 
577
- Person.new.should_not have_and_belong_to_many(:relatives)
715
+ expect(Person.new).not_to have_and_belong_to_many(:relatives)
578
716
  end
579
717
 
580
718
  it 'rejects an association of the wrong type' do
581
- define_model :relative, :person_id => :integer
719
+ define_model :relative, person_id: :integer
582
720
  define_model :person do
583
721
  has_many :relatives
584
722
  end
585
723
 
586
- Person.new.should_not have_and_belong_to_many(:relatives)
724
+ expect(Person.new).not_to have_and_belong_to_many(:relatives)
587
725
  end
588
726
 
589
727
  it 'accepts an association with a valid :conditions option' do
590
- define_model :relative, :adopted => :boolean
728
+ define_model :relative, adopted: :boolean
591
729
  define_model(:person).tap do |model|
592
- define_association_with_conditions(model, :has_and_belongs_to_many, :relatives, :adopted => true)
730
+ define_association_with_conditions(model, :has_and_belongs_to_many, :relatives, adopted: true)
593
731
  end
594
- define_model :people_relative, :id => false, :person_id => :integer,
595
- :relative_id => :integer
732
+ define_model :people_relative, id: false, person_id: :integer,
733
+ relative_id: :integer
596
734
 
597
- Person.new.should have_and_belong_to_many(:relatives).conditions(:adopted => true)
735
+ expect(Person.new).to have_and_belong_to_many(:relatives).conditions(adopted: true)
598
736
  end
599
737
 
600
738
  it 'rejects an association with a bad :conditions option' do
601
- define_model :relative, :adopted => :boolean
739
+ define_model :relative, adopted: :boolean
602
740
  define_model :person do
603
741
  has_and_belongs_to_many :relatives
604
742
  end
605
- define_model :people_relative, :id => false, :person_id => :integer,
606
- :relative_id => :integer
743
+ define_model :people_relative, id: false, person_id: :integer,
744
+ relative_id: :integer
607
745
 
608
- Person.new.should_not have_and_belong_to_many(:relatives).conditions(:adopted => true)
746
+ expect(Person.new).not_to have_and_belong_to_many(:relatives).conditions(adopted: true)
609
747
  end
610
748
 
611
749
  it 'accepts an association without a :class_name option' do
612
- having_and_belonging_to_many_relatives.
613
- should have_and_belong_to_many(:relatives).class_name('Relative')
750
+ expect(having_and_belonging_to_many_relatives).
751
+ to have_and_belong_to_many(:relatives).class_name('Relative')
614
752
  end
615
753
 
616
754
  it 'accepts an association with a valid :class_name option' do
617
- define_model :person_relative, :adopted => :boolean
755
+ define_model :person_relative, adopted: :boolean
618
756
  define_model :person do
619
- has_and_belongs_to_many :relatives, :class_name => 'PersonRelative'
757
+ has_and_belongs_to_many :relatives, class_name: 'PersonRelative'
620
758
  end
621
759
 
622
- define_model :people_person_relative, :person_id => :integer,
623
- :person_relative_id => :integer
760
+ define_model :people_person_relative, person_id: :integer,
761
+ person_relative_id: :integer
624
762
 
625
- Person.new.should have_and_belong_to_many(:relatives).class_name('PersonRelative')
763
+ expect(Person.new).to have_and_belong_to_many(:relatives).class_name('PersonRelative')
626
764
  end
627
765
 
628
766
  it 'rejects an association with a bad :class_name option' do
629
- having_and_belonging_to_many_relatives.
630
- should_not have_and_belong_to_many(:relatives).class_name('PersonRelatives')
767
+ expect(having_and_belonging_to_many_relatives).
768
+ not_to have_and_belong_to_many(:relatives).class_name('PersonRelatives')
769
+ end
770
+
771
+ it 'rejects an association with non-existent implicit class name' do
772
+ expect(having_and_belonging_to_many_non_existent_class(:person, :relatives)).
773
+ not_to have_and_belong_to_many(:relatives)
774
+ end
775
+
776
+ it 'rejects an association with non-existent explicit class name' do
777
+ expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative')).
778
+ not_to have_and_belong_to_many(:relatives)
779
+ end
780
+
781
+ it 'adds error message when rejecting an association with non-existent class' do
782
+ message = 'Expected Person to have a has_and_belongs_to_many association called relatives (Relative2 does not exist)'
783
+ expect {
784
+ expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative2')).
785
+ to have_and_belong_to_many(:relatives)
786
+ }.to fail_with_message(message)
787
+ end
788
+
789
+ it 'accepts an association with a matching :autosave option' do
790
+ define_model :relatives, adopted: :boolean
791
+ define_model :person do
792
+ has_and_belongs_to_many :relatives, autosave: true
793
+ end
794
+ define_model :people_relative, person_id: :integer,
795
+ relative_id: :integer
796
+ expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
797
+ end
798
+
799
+ it 'rejects an association with a non-matching :autosave option with the correct message' do
800
+ define_model :relatives, adopted: :boolean
801
+ define_model :person do
802
+ has_and_belongs_to_many :relatives
803
+ end
804
+ define_model :people_relative, person_id: :integer,
805
+ relative_id: :integer
806
+
807
+ message = 'Expected Person to have a has_and_belongs_to_many association called relatives (relatives should have autosave set to true)'
808
+ expect {
809
+ expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
810
+ }.to fail_with_message(message)
631
811
  end
632
812
 
633
813
  context 'validate' do
634
814
  it 'accepts when the :validate option matches' do
635
- having_and_belonging_to_many_relatives(:validate => false).
636
- should have_and_belong_to_many(:relatives).validate(false)
815
+ expect(having_and_belonging_to_many_relatives(validate: false)).
816
+ to have_and_belong_to_many(:relatives).validate(false)
637
817
  end
638
818
 
639
819
  it 'rejects when the :validate option does not match' do
640
- having_and_belonging_to_many_relatives(:validate => true).
641
- should have_and_belong_to_many(:relatives).validate(false)
820
+ expect(having_and_belonging_to_many_relatives(validate: true)).
821
+ to have_and_belong_to_many(:relatives).validate(false)
642
822
  end
643
823
 
644
824
  it 'assumes validate() means validate(true)' do
645
- having_and_belonging_to_many_relatives(:validate => false).
646
- should_not have_and_belong_to_many(:relatives).validate
825
+ expect(having_and_belonging_to_many_relatives(validate: false)).
826
+ not_to have_and_belong_to_many(:relatives).validate
647
827
  end
648
828
 
649
829
  it 'matches validate(false) to having no validate option specified' do
650
- having_and_belonging_to_many_relatives.
651
- should have_and_belong_to_many(:relatives).validate(false)
830
+ expect(having_and_belonging_to_many_relatives).
831
+ to have_and_belong_to_many(:relatives).validate(false)
652
832
  end
653
833
  end
654
834
 
655
835
  def having_and_belonging_to_many_relatives(options = {})
656
836
  define_model :relative
657
- define_model :people_relative, :id => false, :person_id => :integer,
658
- :relative_id => :integer
837
+ define_model :people_relative, id: false, person_id: :integer,
838
+ relative_id: :integer
659
839
  define_model :person do
660
840
  has_and_belongs_to_many :relatives
661
841
  end.new
662
842
  end
843
+
844
+ def having_and_belonging_to_many_non_existent_class(model_name, assoc_name, options = {})
845
+ define_model model_name do
846
+ has_and_belongs_to_many assoc_name, options
847
+ end.new
848
+ end
663
849
  end
664
850
 
665
851
  def define_association_with_conditions(model, macro, name, conditions, other_options={})