shoulda-matchers 4.0.0.rc1 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +72 -40
  4. data/lib/shoulda/matchers/action_controller.rb +2 -0
  5. data/lib/shoulda/matchers/active_model.rb +2 -3
  6. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +1 -0
  7. data/lib/shoulda/matchers/active_record.rb +2 -0
  8. data/lib/shoulda/matchers/active_record/association_matcher.rb +34 -0
  9. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +27 -4
  10. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +27 -4
  11. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +1 -1
  12. data/lib/shoulda/matchers/independent.rb +2 -1
  13. data/lib/shoulda/matchers/rails_shim.rb +5 -9
  14. data/lib/shoulda/matchers/version.rb +1 -1
  15. data/lib/shoulda/matchers/warn.rb +1 -0
  16. data/shoulda-matchers.gemspec +11 -3
  17. metadata +13 -340
  18. data/.gitignore +0 -12
  19. data/.hound.yml +0 -3
  20. data/.hound/ruby.yml +0 -1062
  21. data/.python-version +0 -1
  22. data/.rubocop.yml +0 -15
  23. data/.travis.yml +0 -21
  24. data/.yardopts +0 -10
  25. data/Appraisals +0 -105
  26. data/CONTRIBUTING.md +0 -172
  27. data/Gemfile +0 -15
  28. data/Gemfile.lock +0 -59
  29. data/MAINTAINING.md +0 -250
  30. data/NEWS.md +0 -1235
  31. data/Rakefile +0 -46
  32. data/bin/setup +0 -190
  33. data/custom_plan.rb +0 -104
  34. data/doc_config/gh-pages/index.html.erb +0 -9
  35. data/doc_config/yard/setup.rb +0 -22
  36. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -5967
  37. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +0 -12
  38. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +0 -66
  39. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +0 -69
  40. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +0 -312
  41. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -26
  42. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +0 -1
  43. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +0 -8
  44. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -281
  45. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +0 -1
  46. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +0 -289
  47. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +0 -6
  48. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +0 -35
  49. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +0 -14
  50. data/doc_config/yard/templates/default/layout/html/fonts.erb +0 -1
  51. data/doc_config/yard/templates/default/layout/html/footer.erb +0 -6
  52. data/doc_config/yard/templates/default/layout/html/layout.erb +0 -23
  53. data/doc_config/yard/templates/default/layout/html/search.erb +0 -13
  54. data/doc_config/yard/templates/default/layout/html/setup.rb +0 -40
  55. data/doc_config/yard/templates/default/method_details/html/source.erb +0 -10
  56. data/doc_config/yard/templates/default/module/html/box_info.erb +0 -31
  57. data/gemfiles/4.2.gemfile +0 -39
  58. data/gemfiles/4.2.gemfile.lock +0 -246
  59. data/gemfiles/5.0.gemfile +0 -37
  60. data/gemfiles/5.0.gemfile.lock +0 -238
  61. data/gemfiles/5.1.gemfile +0 -38
  62. data/gemfiles/5.1.gemfile.lock +0 -254
  63. data/gemfiles/5.2.gemfile +0 -40
  64. data/gemfiles/5.2.gemfile.lock +0 -273
  65. data/script/install_gems_in_all_appraisals +0 -16
  66. data/script/run_all_tests +0 -16
  67. data/script/supported_ruby_versions +0 -7
  68. data/script/update_gem_in_all_appraisals +0 -17
  69. data/script/update_gems_in_all_appraisals +0 -16
  70. data/spec/acceptance/active_model_integration_spec.rb +0 -23
  71. data/spec/acceptance/independent_matchers_spec.rb +0 -125
  72. data/spec/acceptance/multiple_libraries_integration_spec.rb +0 -55
  73. data/spec/acceptance/rails_integration_spec.rb +0 -156
  74. data/spec/acceptance_spec_helper.rb +0 -23
  75. data/spec/doublespeak_spec_helper.rb +0 -2
  76. data/spec/report_warnings.rb +0 -7
  77. data/spec/spec_helper.rb +0 -20
  78. data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +0 -133
  79. data/spec/support/acceptance/helpers.rb +0 -33
  80. data/spec/support/acceptance/helpers/active_model_helpers.rb +0 -11
  81. data/spec/support/acceptance/helpers/array_helpers.rb +0 -13
  82. data/spec/support/acceptance/helpers/base_helpers.rb +0 -19
  83. data/spec/support/acceptance/helpers/command_helpers.rb +0 -68
  84. data/spec/support/acceptance/helpers/file_helpers.rb +0 -19
  85. data/spec/support/acceptance/helpers/gem_helpers.rb +0 -31
  86. data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -11
  87. data/spec/support/acceptance/helpers/n_unit_helpers.rb +0 -25
  88. data/spec/support/acceptance/helpers/pluralization_helpers.rb +0 -13
  89. data/spec/support/acceptance/helpers/rails_migration_helpers.rb +0 -21
  90. data/spec/support/acceptance/helpers/rails_version_helpers.rb +0 -11
  91. data/spec/support/acceptance/helpers/rspec_helpers.rb +0 -24
  92. data/spec/support/acceptance/helpers/ruby_version_helpers.rb +0 -9
  93. data/spec/support/acceptance/helpers/step_helpers.rb +0 -127
  94. data/spec/support/acceptance/matchers/have_output.rb +0 -31
  95. data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +0 -55
  96. data/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +0 -103
  97. data/spec/support/tests/bundle.rb +0 -94
  98. data/spec/support/tests/command_runner.rb +0 -230
  99. data/spec/support/tests/current_bundle.rb +0 -55
  100. data/spec/support/tests/database.rb +0 -28
  101. data/spec/support/tests/database_adapters/postgresql.rb +0 -25
  102. data/spec/support/tests/database_adapters/sqlite3.rb +0 -26
  103. data/spec/support/tests/database_configuration.rb +0 -33
  104. data/spec/support/tests/database_configuration_registry.rb +0 -28
  105. data/spec/support/tests/filesystem.rb +0 -100
  106. data/spec/support/tests/version.rb +0 -45
  107. data/spec/support/unit/active_record/create_table.rb +0 -54
  108. data/spec/support/unit/attribute.rb +0 -45
  109. data/spec/support/unit/capture.rb +0 -46
  110. data/spec/support/unit/change_value.rb +0 -111
  111. data/spec/support/unit/create_model_arguments/basic.rb +0 -135
  112. data/spec/support/unit/create_model_arguments/has_many.rb +0 -15
  113. data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +0 -74
  114. data/spec/support/unit/helpers/action_pack_versions.rb +0 -22
  115. data/spec/support/unit/helpers/active_model_helpers.rb +0 -27
  116. data/spec/support/unit/helpers/active_model_versions.rb +0 -32
  117. data/spec/support/unit/helpers/active_record_versions.rb +0 -44
  118. data/spec/support/unit/helpers/active_resource_builder.rb +0 -27
  119. data/spec/support/unit/helpers/allow_value_matcher_helpers.rb +0 -15
  120. data/spec/support/unit/helpers/class_builder.rb +0 -90
  121. data/spec/support/unit/helpers/column_type_helpers.rb +0 -26
  122. data/spec/support/unit/helpers/confirmation_matcher_helpers.rb +0 -17
  123. data/spec/support/unit/helpers/controller_builder.rb +0 -63
  124. data/spec/support/unit/helpers/database_helpers.rb +0 -20
  125. data/spec/support/unit/helpers/i18n_faker.rb +0 -15
  126. data/spec/support/unit/helpers/mailer_builder.rb +0 -12
  127. data/spec/support/unit/helpers/message_helpers.rb +0 -19
  128. data/spec/support/unit/helpers/model_builder.rb +0 -114
  129. data/spec/support/unit/helpers/rails_versions.rb +0 -42
  130. data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +0 -44
  131. data/spec/support/unit/i18n.rb +0 -7
  132. data/spec/support/unit/load_environment.rb +0 -12
  133. data/spec/support/unit/matchers/deprecate.rb +0 -60
  134. data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +0 -51
  135. data/spec/support/unit/matchers/fail_with_message_matcher.rb +0 -64
  136. data/spec/support/unit/matchers/print_warning_including.rb +0 -67
  137. data/spec/support/unit/model_creation_strategies/active_model.rb +0 -111
  138. data/spec/support/unit/model_creation_strategies/active_record.rb +0 -77
  139. data/spec/support/unit/model_creators.rb +0 -19
  140. data/spec/support/unit/model_creators/active_model.rb +0 -39
  141. data/spec/support/unit/model_creators/active_record.rb +0 -42
  142. data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +0 -95
  143. data/spec/support/unit/model_creators/active_record/has_many.rb +0 -67
  144. data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +0 -42
  145. data/spec/support/unit/model_creators/basic.rb +0 -102
  146. data/spec/support/unit/rails_application.rb +0 -151
  147. data/spec/support/unit/record_builder_with_i18n_validation_message.rb +0 -69
  148. data/spec/support/unit/record_validating_confirmation_builder.rb +0 -54
  149. data/spec/support/unit/record_with_different_error_attribute_builder.rb +0 -92
  150. data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +0 -79
  151. data/spec/support/unit/shared_examples/numerical_submatcher.rb +0 -17
  152. data/spec/support/unit/shared_examples/set_session_or_flash.rb +0 -360
  153. data/spec/support/unit/validation_matcher_scenario.rb +0 -60
  154. data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +0 -82
  155. data/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +0 -28
  156. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +0 -629
  157. data/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +0 -42
  158. data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +0 -76
  159. data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +0 -62
  160. data/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +0 -90
  161. data/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +0 -31
  162. data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +0 -330
  163. data/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb +0 -30
  164. data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +0 -67
  165. data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +0 -17
  166. data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +0 -562
  167. data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -117
  168. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +0 -829
  169. data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -86
  170. data/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +0 -20
  171. data/spec/unit/shoulda/matchers/active_model/helpers_spec.rb +0 -162
  172. data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +0 -290
  173. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +0 -109
  174. data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +0 -172
  175. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -264
  176. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -1049
  177. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -335
  178. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +0 -1865
  179. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -406
  180. data/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -107
  181. data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +0 -1672
  182. data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +0 -251
  183. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +0 -690
  184. data/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +0 -111
  185. data/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +0 -85
  186. data/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +0 -41
  187. data/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb +0 -169
  188. data/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +0 -86
  189. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +0 -1682
  190. data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +0 -190
  191. data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +0 -21
  192. data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +0 -271
  193. data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +0 -77
  194. data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +0 -72
  195. data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +0 -101
  196. data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +0 -78
  197. data/spec/unit/shoulda/matchers/doublespeak_spec.rb +0 -27
  198. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb +0 -43
  199. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +0 -650
  200. data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +0 -406
  201. data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +0 -252
  202. data/spec/unit_spec_helper.rb +0 -54
  203. data/spec/warnings_spy.rb +0 -64
  204. data/spec/warnings_spy/filesystem.rb +0 -45
  205. data/spec/warnings_spy/partitioner.rb +0 -36
  206. data/spec/warnings_spy/reader.rb +0 -53
  207. data/spec/warnings_spy/reporter.rb +0 -88
  208. data/tasks/documentation.rb +0 -199
  209. data/zeus.json +0 -11
@@ -1,1672 +0,0 @@
1
- require 'unit_spec_helper'
2
-
3
- describe Shoulda::Matchers::ActiveRecord::AssociationMatcher, type: :model do
4
- context 'belong_to' do
5
- it 'accepts a good association with the default foreign key' do
6
- expect(belonging_to_parent).to belong_to(:parent)
7
- end
8
-
9
- it 'rejects a nonexistent association' do
10
- expect(define_model(:child).new).not_to belong_to(:parent)
11
- end
12
-
13
- it 'rejects an association of the wrong type' do
14
- define_model :parent, child_id: :integer
15
- expect(define_model(:child) { has_one :parent }.new).not_to belong_to(:parent)
16
- end
17
-
18
- it 'rejects an association that has a nonexistent foreign key' do
19
- define_model :parent
20
- expect(define_model(:child) { belongs_to :parent }.new).not_to belong_to(:parent)
21
- end
22
-
23
- it 'accepts an association with an existing custom foreign key' do
24
- define_model :parent
25
- define_model :child, guardian_id: :integer do
26
- belongs_to :parent, foreign_key: 'guardian_id'
27
- end
28
-
29
- expect(Child.new).to belong_to(:parent)
30
- end
31
-
32
- it 'accepts an association using an existing custom primary key' do
33
- define_model :parent
34
- define_model :child, parent_id: :integer, custom_primary_key: :integer do
35
- belongs_to :parent, primary_key: :custom_primary_key
36
- end
37
- expect(Child.new).to belong_to(:parent).with_primary_key(:custom_primary_key)
38
- end
39
-
40
- it 'rejects an association with a bad :primary_key option' do
41
- matcher = belong_to(:parent).with_primary_key(:custom_primary_key)
42
-
43
- expect(belonging_to_parent).not_to matcher
44
-
45
- expect(matcher.failure_message).to match(/Child does not have a custom_primary_key primary key/)
46
- end
47
-
48
- it 'accepts a polymorphic association' do
49
- define_model :child, parent_type: :string, parent_id: :integer do
50
- belongs_to :parent, polymorphic: true
51
- end
52
-
53
- expect(Child.new).to belong_to(:parent)
54
- end
55
-
56
- it 'accepts an association with a valid :dependent option' do
57
- expect(belonging_to_parent(dependent: :destroy)).
58
- to belong_to(:parent).dependent(:destroy)
59
- end
60
-
61
- it 'rejects an association with a bad :dependent option' do
62
- expect(belonging_to_parent).not_to belong_to(:parent).dependent(:destroy)
63
- end
64
-
65
- it 'accepts an association with a valid :counter_cache option' do
66
- expect(belonging_to_parent(counter_cache: :attribute_count)).
67
- to belong_to(:parent).counter_cache(:attribute_count)
68
- end
69
-
70
- it 'defaults :counter_cache to true' do
71
- expect(belonging_to_parent(counter_cache: true)).
72
- to belong_to(:parent).counter_cache
73
- end
74
-
75
- it 'rejects an association with a bad :counter_cache option' do
76
- expect(belonging_to_parent(counter_cache: :attribute_count)).
77
- not_to belong_to(:parent).counter_cache(true)
78
- end
79
-
80
- it 'rejects an association that has no :counter_cache option' do
81
- expect(belonging_to_parent).not_to belong_to(:parent).counter_cache
82
- end
83
-
84
- it 'accepts an association with a valid :inverse_of option' do
85
- expect(belonging_to_with_inverse(:parent, :children)).
86
- to belong_to(:parent).inverse_of(:children)
87
- end
88
-
89
- it 'rejects an association with a bad :inverse_of option' do
90
- expect(belonging_to_with_inverse(:parent, :other_children)).
91
- not_to belong_to(:parent).inverse_of(:children)
92
- end
93
-
94
- it 'rejects an association that has no :inverse_of option' do
95
- expect(belonging_to_parent).
96
- not_to belong_to(:parent).inverse_of(:children)
97
- end
98
-
99
- it 'accepts an association with a valid :conditions option' do
100
- define_model :parent, adopter: :boolean
101
- define_model(:child, parent_id: :integer).tap do |model|
102
- define_association_with_conditions(model, :belongs_to, :parent, adopter: true)
103
- end
104
-
105
- expect(Child.new).to belong_to(:parent).conditions(adopter: true)
106
- end
107
-
108
- it 'rejects an association with a bad :conditions option' do
109
- define_model :parent, adopter: :boolean
110
- define_model :child, parent_id: :integer do
111
- belongs_to :parent
112
- end
113
-
114
- expect(Child.new).not_to belong_to(:parent).conditions(adopter: true)
115
- end
116
-
117
- it 'accepts an association without a :class_name option' do
118
- expect(belonging_to_parent).to belong_to(:parent).class_name('Parent')
119
- end
120
-
121
- it 'accepts an association with a valid :class_name option' do
122
- define_model :tree_parent
123
- define_model :child, parent_id: :integer do
124
- belongs_to :parent, class_name: 'TreeParent'
125
- end
126
-
127
- expect(Child.new).to belong_to(:parent).class_name('TreeParent')
128
- end
129
-
130
- it 'rejects an association with a bad :class_name option' do
131
- expect(belonging_to_parent).not_to belong_to(:parent).class_name('TreeChild')
132
- end
133
-
134
- it 'rejects an association with non-existent implicit class name' do
135
- expect(belonging_to_non_existent_class(:child, :parent)).not_to belong_to(:parent)
136
- end
137
-
138
- it 'rejects an association with non-existent explicit class name' do
139
- expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent')).not_to belong_to(:parent)
140
- end
141
-
142
- it 'adds error message when rejecting an association with non-existent class' do
143
- message = 'Expected Child to have a belongs_to association called parent (Parent2 does not exist)'
144
- expect {
145
- expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent2')).to belong_to(:parent)
146
- }.to fail_with_message(message)
147
- end
148
-
149
- it 'accepts an association with a namespaced class name' do
150
- define_module 'Models'
151
- define_model 'Models::Organization'
152
- user_model = define_model 'Models::User', organization_id: :integer do
153
- belongs_to :organization, class_name: 'Organization'
154
- end
155
-
156
- expect(user_model.new).
157
- to belong_to(:organization).
158
- class_name('Organization')
159
- end
160
-
161
- it 'resolves class_name within the context of the namespace before the global namespace' do
162
- define_module 'Models'
163
- define_model 'Organization'
164
- define_model 'Models::Organization'
165
- user_model = define_model 'Models::User', organization_id: :integer do
166
- belongs_to :organization, class_name: 'Organization'
167
- end
168
-
169
- expect(user_model.new).
170
- to belong_to(:organization).
171
- class_name('Organization')
172
- end
173
-
174
- it 'accepts an association with a matching :autosave option' do
175
- define_model :parent, adopter: :boolean
176
- define_model :child, parent_id: :integer do
177
- belongs_to :parent, autosave: true
178
- end
179
- expect(Child.new).to belong_to(:parent).autosave(true)
180
- end
181
-
182
- it 'rejects an association with a non-matching :autosave option with the correct message' do
183
- define_model :parent, adopter: :boolean
184
- define_model :child, parent_id: :integer do
185
- belongs_to :parent, autosave: false
186
- end
187
-
188
- message = 'Expected Child to have a belongs_to association called parent (parent should have autosave set to true)'
189
- expect {
190
- expect(Child.new).to belong_to(:parent).autosave(true)
191
- }.to fail_with_message(message)
192
- end
193
-
194
- context 'an association with a :validate option' do
195
- [false, true].each do |validate_value|
196
- context "when the model has validate: #{validate_value}" do
197
- it 'accepts a matching validate option' do
198
- expect(belonging_to_parent(validate: validate_value)).
199
- to belong_to(:parent).validate(validate_value)
200
- end
201
-
202
- it 'rejects a non-matching validate option' do
203
- expect(belonging_to_parent(validate: validate_value)).
204
- not_to belong_to(:parent).validate(!validate_value)
205
- end
206
-
207
- it 'defaults to validate(true)' do
208
- if validate_value
209
- expect(belonging_to_parent(validate: validate_value)).
210
- to belong_to(:parent).validate
211
- else
212
- expect(belonging_to_parent(validate: validate_value)).
213
- not_to belong_to(:parent).validate
214
- end
215
- end
216
-
217
- it 'will not break matcher when validate option is unspecified' do
218
- expect(belonging_to_parent(validate: validate_value)).to belong_to(:parent)
219
- end
220
- end
221
- end
222
- end
223
-
224
- context 'an association without a :validate option' do
225
- it 'accepts validate(false)' do
226
- expect(belonging_to_parent).to belong_to(:parent).validate(false)
227
- end
228
-
229
- it 'rejects validate(true)' do
230
- expect(belonging_to_parent).not_to belong_to(:parent).validate(true)
231
- end
232
-
233
- it 'rejects validate()' do
234
- expect(belonging_to_parent).not_to belong_to(:parent).validate
235
- end
236
- end
237
-
238
- context 'an association with a :touch option' do
239
- [false, true].each do |touch_value|
240
- context "when the model has touch: #{touch_value}" do
241
- it 'accepts a matching touch option' do
242
- expect(belonging_to_parent(touch: touch_value)).
243
- to belong_to(:parent).touch(touch_value)
244
- end
245
-
246
- it 'rejects a non-matching touch option' do
247
- expect(belonging_to_parent(touch: touch_value)).
248
- not_to belong_to(:parent).touch(!touch_value)
249
- end
250
-
251
- it 'defaults to touch(true)' do
252
- if touch_value
253
- expect(belonging_to_parent(touch: touch_value)).
254
- to belong_to(:parent).touch
255
- else
256
- expect(belonging_to_parent(touch: touch_value)).
257
- not_to belong_to(:parent).touch
258
- end
259
- end
260
-
261
- it 'will not break matcher when touch option is unspecified' do
262
- expect(belonging_to_parent(touch: touch_value)).to belong_to(:parent)
263
- end
264
- end
265
- end
266
- end
267
-
268
- context 'an association without a :touch option' do
269
- it 'accepts touch(false)' do
270
- expect(belonging_to_parent).to belong_to(:parent).touch(false)
271
- end
272
-
273
- it 'rejects touch(true)' do
274
- expect(belonging_to_parent).not_to belong_to(:parent).touch(true)
275
- end
276
-
277
- it 'rejects touch()' do
278
- expect(belonging_to_parent).not_to belong_to(:parent).touch
279
- end
280
- end
281
-
282
- context 'given the association is neither configured to be required nor optional' do
283
- context 'when qualified with required(true)' do
284
- if active_record_supports_optional_for_associations?
285
- context 'when belongs_to is configured to be required by default' do
286
- it 'passes' do
287
- configuring_default_belongs_to_requiredness(true) do
288
- expect(belonging_to_parent).to belong_to(:parent).required(true)
289
- end
290
- end
291
- end
292
-
293
- context 'when belongs_to is not configured to be required by default' do
294
- it 'fails with an appropriate message' do
295
- configuring_default_belongs_to_requiredness(false) do
296
- assertion = lambda do
297
- expect(belonging_to_parent).
298
- to belong_to(:parent).required(true)
299
- end
300
-
301
- message = format_message(<<-MESSAGE, one_line: true)
302
- Expected Child to have a belongs_to association called parent
303
- (the association should have been defined with `required:
304
- true`, but was not)
305
- MESSAGE
306
-
307
- expect(&assertion).to fail_with_message(message)
308
- end
309
- end
310
- end
311
- else
312
- it 'fails with an appropriate message' do
313
- assertion = lambda do
314
- expect(belonging_to_parent).
315
- to belong_to(:parent).required(true)
316
- end
317
-
318
- message = format_message(<<-MESSAGE, one_line: true)
319
- Expected Child to have a belongs_to association called parent
320
- (the association should have been defined with `required:
321
- true`, but was not)
322
- MESSAGE
323
-
324
- expect(&assertion).to fail_with_message(message)
325
- end
326
- end
327
- end
328
-
329
- context 'when qualified with required(false)' do
330
- if active_record_supports_optional_for_associations?
331
- context 'when belongs_to is configured to be required by default' do
332
- it 'fails with an appropriate message' do
333
- configuring_default_belongs_to_requiredness(true) do
334
- assertion = lambda do
335
- expect(belonging_to_parent).
336
- to belong_to(:parent).required(false)
337
- end
338
-
339
- message = format_message(<<-MESSAGE, one_line: true)
340
- Expected Child to have a belongs_to association called parent
341
- (the association should have been defined with `required:
342
- false`, but was not)
343
- MESSAGE
344
-
345
- expect(&assertion).to fail_with_message(message)
346
- end
347
- end
348
- end
349
-
350
- context 'when belongs_to is not configured to be required by default' do
351
- it 'passes' do
352
- configuring_default_belongs_to_requiredness(false) do
353
- expect(belonging_to_parent).to belong_to(:parent).required(false)
354
- end
355
- end
356
- end
357
- else
358
- it 'passes' do
359
- expect(belonging_to_parent).to belong_to(:parent).required(false)
360
- end
361
- end
362
- end
363
-
364
- context 'when qualified with optional' do
365
- if active_record_supports_optional_for_associations?
366
- context 'when belongs_to is configured to be required by default' do
367
- it 'fails with an appropriate message' do
368
- configuring_default_belongs_to_requiredness(true) do
369
- assertion = lambda do
370
- expect(belonging_to_parent).
371
- to belong_to(:parent).optional
372
- end
373
-
374
- message = format_message(<<-MESSAGE, one_line: true)
375
- Expected Child to have a belongs_to association called parent (the
376
- association should have been defined with `optional: true`, but
377
- was not)
378
- MESSAGE
379
-
380
- expect(&assertion).to fail_with_message(message)
381
- end
382
- end
383
- end
384
-
385
- context 'when belongs_to is not configured to be required by default' do
386
- it 'passes' do
387
- configuring_default_belongs_to_requiredness(false) do
388
- expect(belonging_to_parent).to belong_to(:parent).optional
389
- end
390
- end
391
- end
392
- else
393
- it 'passes' do
394
- expect(belonging_to_parent).to belong_to(:parent).optional
395
- end
396
- end
397
- end
398
-
399
- context 'when qualified with nothing' do
400
- if active_record_supports_optional_for_associations?
401
- context 'when belongs_to is configured to be required by default' do
402
- it 'passes' do
403
- configuring_default_belongs_to_requiredness(true) do
404
- expect(belonging_to_parent).to belong_to(:parent)
405
- end
406
- end
407
- end
408
-
409
- context 'when belongs_to is not configured to be required by default' do
410
- it 'passes' do
411
- configuring_default_belongs_to_requiredness(false) do
412
- expect(belonging_to_parent).to belong_to(:parent)
413
- end
414
- end
415
-
416
- context 'and a presence validation is on the attribute instead of using required: true' do
417
- it 'passes' do
418
- configuring_default_belongs_to_requiredness(false) do
419
- record = belonging_to_parent do
420
- validates_presence_of :parent
421
- end
422
-
423
- expect(record).to belong_to(:parent)
424
- end
425
- end
426
- end
427
-
428
- context 'and a presence validation is on the attribute with a condition' do
429
- context 'and the condition is true' do
430
- it 'passes' do
431
- configuring_default_belongs_to_requiredness(false) do
432
- child_model = create_child_model_belonging_to_parent do
433
- attr_accessor :condition
434
- validates_presence_of :parent, if: :condition
435
- end
436
-
437
- record = child_model.new(condition: true)
438
-
439
- expect(record).to belong_to(:parent)
440
- end
441
- end
442
- end
443
-
444
- context 'and the condition is false' do
445
- it 'passes' do
446
- configuring_default_belongs_to_requiredness(false) do
447
- child_model = create_child_model_belonging_to_parent do
448
- attr_accessor :condition
449
- validates_presence_of :parent, if: :condition
450
- end
451
-
452
- record = child_model.new(condition: false)
453
-
454
- expect(record).to belong_to(:parent)
455
- end
456
- end
457
- end
458
- end
459
- end
460
- else
461
- it 'passes' do
462
- expect(belonging_to_parent).to belong_to(:parent)
463
- end
464
-
465
- context 'and a presence validation is on the attribute instead of using required: true' do
466
- it 'passes' do
467
- record = belonging_to_parent do
468
- validates_presence_of :parent
469
- end
470
-
471
- expect(record).to belong_to(:parent)
472
- end
473
- end
474
-
475
- context 'and a presence validation is on the attribute with a condition' do
476
- context 'and the condition is true' do
477
- it 'passes' do
478
- child_model = create_child_model_belonging_to_parent do
479
- attr_accessor :condition
480
- validates_presence_of :parent, if: :condition
481
- end
482
-
483
- record = child_model.new(condition: true)
484
-
485
- expect(record).to belong_to(:parent)
486
- end
487
- end
488
-
489
- context 'and the condition is false' do
490
- it 'passes' do
491
- child_model = create_child_model_belonging_to_parent do
492
- attr_accessor :condition
493
- validates_presence_of :parent, if: :condition
494
- end
495
-
496
- record = child_model.new(condition: false)
497
-
498
- expect(record).to belong_to(:parent)
499
- end
500
- end
501
- end
502
- end
503
- end
504
- end
505
-
506
- context 'given the association is configured with required: true' do
507
- context 'when qualified with required(true)' do
508
- it 'passes' do
509
- expect(belonging_to_parent(required: true)).
510
- to belong_to(:parent).required(true)
511
- end
512
- end
513
-
514
- context 'when qualified with required(false)' do
515
- it 'passes' do
516
- assertion = lambda do
517
- expect(belonging_to_parent(required: true)).
518
- to belong_to(:parent).required(false)
519
- end
520
-
521
- message = format_message(<<-MESSAGE, one_line: true)
522
- Expected Child to have a belongs_to association called parent (the
523
- association should have been defined with `required: false`, but
524
- was not)
525
- MESSAGE
526
-
527
- expect(&assertion).to fail_with_message(message)
528
- end
529
- end
530
-
531
- context 'when qualified with optional' do
532
- it 'fails with an appropriate message' do
533
- assertion = lambda do
534
- expect(belonging_to_parent(required: true)).
535
- to belong_to(:parent).optional
536
- end
537
-
538
- message = format_message(<<-MESSAGE, one_line: true)
539
- Expected Child to have a belongs_to association called parent (the
540
- association should have been defined with `optional: true`, but
541
- was not)
542
- MESSAGE
543
-
544
- expect(&assertion).to fail_with_message(message)
545
- end
546
- end
547
-
548
- context 'when qualified with nothing' do
549
- it 'passes' do
550
- expect(belonging_to_parent(required: true)).to belong_to(:parent)
551
- end
552
- end
553
- end
554
-
555
- if active_record_supports_optional_for_associations?
556
- context 'given the association is configured as optional: true' do
557
- context 'when qualified with required(true)' do
558
- it 'fails with an appropriate message' do
559
- assertion = lambda do
560
- expect(belonging_to_parent(optional: true)).
561
- to belong_to(:parent).required(true)
562
- end
563
-
564
- message = format_message(<<-MESSAGE, one_line: true)
565
- Expected Child to have a belongs_to association called parent (the
566
- association should have been defined with `required: true`, but
567
- was not)
568
- MESSAGE
569
-
570
- expect(&assertion).to fail_with_message(message)
571
- end
572
- end
573
-
574
- context 'when qualified with required(false)' do
575
- it 'passes' do
576
- expect(belonging_to_parent(optional: true)).
577
- to belong_to(:parent).required(false)
578
- end
579
- end
580
-
581
- context 'when qualified with optional' do
582
- it 'passes' do
583
- expect(belonging_to_parent(optional: true)).
584
- to belong_to(:parent).optional
585
- end
586
- end
587
-
588
- context 'when qualified with nothing' do
589
- it 'fails with an appropriate message' do
590
- assertion = lambda do
591
- expect(belonging_to_parent(optional: true)).
592
- to belong_to(:parent)
593
- end
594
-
595
- message = format_message(<<-MESSAGE, one_line: true)
596
- Expected Child to have a belongs_to association called parent (the
597
- association should have been defined with `required: true`, but
598
- was not)
599
- MESSAGE
600
-
601
- expect(&assertion).to fail_with_message(message)
602
- end
603
- end
604
- end
605
- end
606
-
607
- def belonging_to_parent(options = {}, parent_options = {}, &block)
608
- child_model = create_child_model_belonging_to_parent(
609
- options,
610
- parent_options,
611
- &block
612
- )
613
- child_model.new
614
- end
615
-
616
- def create_child_model_belonging_to_parent(
617
- options = {},
618
- parent_options = {},
619
- &block
620
- )
621
- define_model(:parent, parent_options)
622
-
623
- define_model :child, parent_id: :integer do
624
- belongs_to :parent, options
625
-
626
- if block
627
- class_eval(&block)
628
- end
629
- end
630
- end
631
-
632
- def belonging_to_with_inverse(association, inverse_association)
633
- parent_model_name = association.to_s.singularize
634
- child_model_name = inverse_association.to_s.singularize
635
- parent_foreign_key = "#{parent_model_name}_id"
636
-
637
- define_model parent_model_name do
638
- has_many inverse_association
639
- end
640
-
641
- child_model = define_model(
642
- child_model_name,
643
- parent_foreign_key => :integer,
644
- ) do
645
- belongs_to association, inverse_of: inverse_association
646
- end
647
-
648
- child_model.new
649
- end
650
-
651
- def belonging_to_non_existent_class(model_name, assoc_name, options = {})
652
- define_model model_name, "#{assoc_name}_id" => :integer do
653
- belongs_to assoc_name, options
654
- end.new
655
- end
656
- end
657
-
658
- context 'have_many' do
659
- it 'accepts a valid association without any options' do
660
- expect(having_many_children).to have_many(:children)
661
- end
662
-
663
- it 'accepts a valid association with a :through option' do
664
- define_model :child
665
- define_model :conception, child_id: :integer,
666
- parent_id: :integer do
667
- belongs_to :child
668
- end
669
- define_model :parent do
670
- has_many :conceptions
671
- has_many :children, through: :conceptions
672
- end
673
- expect(Parent.new).to have_many(:children)
674
- end
675
-
676
- it 'accepts a valid association with an :as option' do
677
- define_model :child, guardian_type: :string, guardian_id: :integer
678
- define_model :parent do
679
- has_many :children, as: :guardian
680
- end
681
-
682
- expect(Parent.new).to have_many(:children)
683
- end
684
-
685
- it 'rejects an association that has a nonexistent foreign key' do
686
- define_model :child
687
- define_model :parent do
688
- has_many :children
689
- end
690
-
691
- expect(Parent.new).not_to have_many(:children)
692
- end
693
-
694
- it 'accepts an association using an existing custom primary key' do
695
- define_model :child, parent_id: :integer
696
- define_model :parent, custom_primary_key: :integer do
697
- has_many :children, primary_key: :custom_primary_key
698
- end
699
- expect(Parent.new).to have_many(:children).with_primary_key(:custom_primary_key)
700
- end
701
-
702
- it 'rejects an association with a bad :primary_key option' do
703
- matcher = have_many(:children).with_primary_key(:custom_primary_key)
704
-
705
- expect(having_many_children).not_to matcher
706
-
707
- expect(matcher.failure_message).to match(/Parent does not have a custom_primary_key primary key/)
708
- end
709
-
710
- it 'rejects an association with a bad :as option' do
711
- define_model :child, caretaker_type: :string,
712
- caretaker_id: :integer
713
- define_model :parent do
714
- has_many :children, as: :guardian
715
- end
716
-
717
- expect(Parent.new).not_to have_many(:children)
718
- end
719
-
720
- it 'rejects an association that has a bad :through option' do
721
- matcher = have_many(:children).through(:conceptions)
722
-
723
- expect(matcher.matches?(having_many_children)).to eq false
724
-
725
- expect(matcher.failure_message).to match(/does not have any relationship to conceptions/)
726
- end
727
-
728
- it 'rejects an association that has the wrong :through option' do
729
- define_model :child
730
-
731
- define_model :conception, child_id: :integer,
732
- parent_id: :integer do
733
- belongs_to :child
734
- end
735
-
736
- define_model :parent do
737
- has_many :conceptions
738
- has_many :relationships
739
- has_many :children, through: :conceptions
740
- end
741
-
742
- matcher = have_many(:children).through(:relationships)
743
- expect(matcher.matches?(Parent.new)).to eq false
744
- expect(matcher.failure_message).to match(/through relationships, but got it through conceptions/)
745
- end
746
-
747
- it 'produces a failure message without exception when association is missing :through option' do
748
- define_model :child
749
- define_model :parent
750
- matcher = have_many(:children).through(:relationships).source(:child)
751
- failure_message = 'Expected Parent to have a has_many association called children (no association called children)'
752
-
753
- matcher.matches?(Parent.new)
754
- expect(matcher.failure_message).to eq failure_message
755
- end
756
-
757
- it 'accepts an association with a valid :dependent option' do
758
- expect(having_many_children(dependent: :destroy)).
759
- to have_many(:children).dependent(:destroy)
760
- end
761
-
762
- it 'rejects an association with a bad :dependent option' do
763
- matcher = have_many(:children).dependent(:destroy)
764
-
765
- expect(having_many_children).not_to matcher
766
-
767
- expect(matcher.failure_message).to match(/children should have destroy dependency/)
768
- end
769
-
770
- it 'accepts an association with a valid :source option' do
771
- expect(having_many_children(source: :user)).
772
- to have_many(:children).source(:user)
773
- end
774
-
775
- it 'rejects an association with a bad :source option' do
776
- matcher = have_many(:children).source(:user)
777
-
778
- expect(having_many_children).not_to matcher
779
-
780
- expect(matcher.failure_message).to match(/children should have user as source option/)
781
- end
782
-
783
- it 'accepts an association with a valid :order option' do
784
- expect(having_many_children(order: :id)).
785
- to have_many(:children).order(:id)
786
- end
787
-
788
- it 'rejects an association with a bad :order option' do
789
- matcher = have_many(:children).order(:id)
790
-
791
- expect(having_many_children).not_to matcher
792
-
793
- expect(matcher.failure_message).to match(/children should be ordered by id/)
794
- end
795
-
796
- it 'accepts an association with a valid :conditions option' do
797
- define_model :child, parent_id: :integer, adopted: :boolean
798
- define_model(:parent).tap do |model|
799
- define_association_with_conditions(model, :has_many, :children, adopted: true)
800
- end
801
-
802
- expect(Parent.new).to have_many(:children).conditions(adopted: true)
803
- end
804
-
805
- it 'rejects an association with a bad :conditions option' do
806
- define_model :child, parent_id: :integer, adopted: :boolean
807
- define_model :parent do
808
- has_many :children
809
- end
810
-
811
- expect(Parent.new).not_to have_many(:children).conditions(adopted: true)
812
- end
813
-
814
- it 'accepts an association without a :class_name option' do
815
- expect(having_many_children).to have_many(:children).class_name('Child')
816
- end
817
-
818
- it 'accepts an association with a valid :class_name option' do
819
- define_model :node, parent_id: :integer
820
- define_model :parent do
821
- has_many :children, class_name: 'Node'
822
- end
823
-
824
- expect(Parent.new).to have_many(:children).class_name('Node')
825
- end
826
-
827
- it 'rejects an association with a bad :class_name option' do
828
- expect(having_many_children).not_to have_many(:children).class_name('Node')
829
- end
830
-
831
- it 'rejects an association with non-existent implicit class name' do
832
- expect(having_many_non_existent_class(:parent, :children)).not_to have_many(:children)
833
- end
834
-
835
- it 'rejects an association with non-existent explicit class name' do
836
- expect(having_many_non_existent_class(:parent, :children, class_name: 'Child')).not_to have_many(:children)
837
- end
838
-
839
- it 'adds error message when rejecting an association with non-existent class' do
840
- message = 'Expected Parent to have a has_many association called children (Child2 does not exist)'
841
- expect {
842
- expect(having_many_non_existent_class(:parent, :children, class_name: 'Child2')).to have_many(:children)
843
- }.to fail_with_message(message)
844
- end
845
-
846
- it 'accepts an association with a namespaced class name' do
847
- define_module 'Models'
848
- define_model 'Models::Friend', user_id: :integer
849
- friend_model = define_model 'Models::User' do
850
- has_many :friends, class_name: 'Friend'
851
- end
852
-
853
- expect(friend_model.new).
854
- to have_many(:friends).
855
- class_name('Friend')
856
- end
857
-
858
- it 'resolves class_name within the context of the namespace before the global namespace' do
859
- define_module 'Models'
860
- define_model 'Friend'
861
- define_model 'Models::Friend', user_id: :integer
862
- friend_model = define_model 'Models::User' do
863
- has_many :friends, class_name: 'Friend'
864
- end
865
-
866
- expect(friend_model.new).
867
- to have_many(:friends).
868
- class_name('Friend')
869
- end
870
-
871
- it 'accepts an association with a matching :autosave option' do
872
- define_model :child, parent_id: :integer
873
- define_model :parent do
874
- has_many :children, autosave: true
875
- end
876
- expect(Parent.new).to have_many(:children).autosave(true)
877
- end
878
-
879
- it 'rejects an association with a non-matching :autosave option with the correct message' do
880
- define_model :child, parent_id: :integer
881
- define_model :parent do
882
- has_many :children, autosave: false
883
- end
884
-
885
- message = 'Expected Parent to have a has_many association called children (children should have autosave set to true)'
886
- expect {
887
- expect(Parent.new).to have_many(:children).autosave(true)
888
- }.to fail_with_message(message)
889
- end
890
-
891
- if rails_5_x?
892
- context 'index_errors' do
893
- it 'accepts an association with a matching :index_errors option' do
894
- define_model :child, parent_id: :integer
895
- define_model :parent do
896
- has_many :children, index_errors: true
897
- end
898
- expect(Parent.new).to have_many(:children).index_errors(true)
899
- end
900
-
901
- it 'rejects an association with a non-matching :index_errors option and returns the correct message' do
902
- define_model :child, parent_id: :integer
903
- define_model :parent do
904
- has_many :children, autosave: false
905
- end
906
-
907
- message =
908
- 'Expected Parent to have a has_many association called children ' +
909
- '(children should have index_errors set to true)'
910
-
911
- expect {
912
- expect(Parent.new).to have_many(:children).index_errors(true)
913
- }.to fail_with_message(message)
914
- end
915
- end
916
- end
917
-
918
- context 'validate' do
919
- it 'accepts when the :validate option matches' do
920
- expect(having_many_children(validate: false)).to have_many(:children).validate(false)
921
- end
922
-
923
- it 'rejects when the :validate option does not match' do
924
- expect(having_many_children(validate: true)).not_to have_many(:children).validate(false)
925
- end
926
-
927
- it 'assumes validate() means validate(true)' do
928
- expect(having_many_children(validate: false)).not_to have_many(:children).validate
929
- end
930
-
931
- it 'matches validate(false) to having no validate option specified' do
932
- expect(having_many_children).to have_many(:children).validate(false)
933
- end
934
- end
935
-
936
- it 'accepts an association with a nonstandard reverse foreign key, using :inverse_of' do
937
- define_model :child, ancestor_id: :integer do
938
- belongs_to :ancestor, inverse_of: :children, class_name: :Parent
939
- end
940
-
941
- define_model :parent do
942
- has_many :children, inverse_of: :ancestor
943
- end
944
-
945
- expect(Parent.new).to have_many(:children)
946
- end
947
-
948
- it 'rejects an association with a nonstandard reverse foreign key, if :inverse_of is not correct' do
949
- define_model :child, mother_id: :integer do
950
- belongs_to :mother, inverse_of: :children, class_name: :Parent
951
- end
952
-
953
- define_model :parent do
954
- has_many :children, inverse_of: :ancestor
955
- end
956
-
957
- expect(Parent.new).not_to have_many(:children)
958
- end
959
-
960
- def having_many_children(options = {})
961
- define_model :child, parent_id: :integer
962
- define_model(:parent).tap do |model|
963
- if options.key?(:order)
964
- order = options.delete(:order)
965
- define_association_with_order(model, :has_many, :children, order, options)
966
- else
967
- model.has_many :children, options
968
- end
969
- end.new
970
- end
971
-
972
- def having_many_non_existent_class(model_name, assoc_name, options = {})
973
- define_model model_name do
974
- has_many assoc_name, options
975
- end.new
976
- end
977
- end
978
-
979
- context 'have_one' do
980
- it 'accepts a valid association without any options' do
981
- expect(having_one_detail).to have_one(:detail)
982
- end
983
-
984
- it 'accepts a valid association with an :as option' do
985
- define_model :detail, detailable_id: :integer,
986
- detailable_type: :string
987
- define_model :person do
988
- has_one :detail, as: :detailable
989
- end
990
-
991
- expect(Person.new).to have_one(:detail)
992
- end
993
-
994
- it 'rejects an association that has a nonexistent foreign key' do
995
- define_model :detail
996
- define_model :person do
997
- has_one :detail
998
- end
999
-
1000
- expect(Person.new).not_to have_one(:detail)
1001
- end
1002
-
1003
- it 'accepts an association with an existing custom foreign key' do
1004
- define_model :detail, detailed_person_id: :integer
1005
- define_model :person do
1006
- has_one :detail, foreign_key: :detailed_person_id
1007
- end
1008
- expect(Person.new).to have_one(:detail).with_foreign_key(:detailed_person_id)
1009
- end
1010
-
1011
- it 'accepts an association using an existing custom primary key' do
1012
- define_model :detail, person_id: :integer
1013
- define_model :person, custom_primary_key: :integer do
1014
- has_one :detail, primary_key: :custom_primary_key
1015
- end
1016
- expect(Person.new).to have_one(:detail).with_primary_key(:custom_primary_key)
1017
- end
1018
-
1019
- it 'rejects an association with a bad :primary_key option' do
1020
- matcher = have_one(:detail).with_primary_key(:custom_primary_key)
1021
-
1022
- expect(having_one_detail).not_to matcher
1023
-
1024
- expect(matcher.failure_message).to match(/Person does not have a custom_primary_key primary key/)
1025
- end
1026
-
1027
- it 'rejects an association with a bad :as option' do
1028
- define_model :detail, detailable_id: :integer,
1029
- detailable_type: :string
1030
- define_model :person do
1031
- has_one :detail, as: :describable
1032
- end
1033
-
1034
- expect(Person.new).not_to have_one(:detail)
1035
- end
1036
-
1037
- it 'accepts an association with a valid :dependent option' do
1038
- dependent_options.each do |option|
1039
- expect(having_one_detail(dependent: option)).
1040
- to have_one(:detail).dependent(option)
1041
- end
1042
- end
1043
-
1044
- it 'accepts any dependent option if true' do
1045
- dependent_options.each do |option|
1046
- expect(having_one_detail(dependent: option)).
1047
- to have_one(:detail).dependent(true)
1048
- end
1049
- end
1050
-
1051
- it 'rejects any dependent options if false' do
1052
- dependent_options.each do |option|
1053
- expect(having_one_detail(dependent: option)).
1054
- to_not have_one(:detail).dependent(false)
1055
- end
1056
- end
1057
-
1058
- it 'accepts a nil dependent option if false' do
1059
- expect(having_one_detail).to have_one(:detail).dependent(false)
1060
- end
1061
-
1062
- it 'rejects an association with a bad :dependent option' do
1063
- matcher = have_one(:detail).dependent(:destroy)
1064
-
1065
- expect(having_one_detail).not_to matcher
1066
-
1067
- expect(matcher.failure_message).to match(/detail should have destroy dependency/)
1068
- end
1069
-
1070
- it 'accepts an association with a valid :order option' do
1071
- expect(having_one_detail(order: :id)).to have_one(:detail).order(:id)
1072
- end
1073
-
1074
- it 'rejects an association with a bad :order option' do
1075
- matcher = have_one(:detail).order(:id)
1076
-
1077
- expect(having_one_detail).not_to matcher
1078
-
1079
- expect(matcher.failure_message).to match(/detail should be ordered by id/)
1080
- end
1081
-
1082
- it 'accepts an association with a valid :conditions option' do
1083
- define_model :detail, person_id: :integer, disabled: :boolean
1084
- define_model(:person).tap do |model|
1085
- define_association_with_conditions(model, :has_one, :detail, disabled: true)
1086
- end
1087
-
1088
- expect(Person.new).to have_one(:detail).conditions(disabled: true)
1089
- end
1090
-
1091
- it 'rejects an association with a bad :conditions option' do
1092
- define_model :detail, person_id: :integer, disabled: :boolean
1093
- define_model :person do
1094
- has_one :detail
1095
- end
1096
-
1097
- expect(Person.new).not_to have_one(:detail).conditions(disabled: true)
1098
- end
1099
-
1100
- it 'accepts an association without a :class_name option' do
1101
- expect(having_one_detail).to have_one(:detail).class_name('Detail')
1102
- end
1103
-
1104
- it 'accepts an association with a valid :class_name option' do
1105
- define_model :person_detail, person_id: :integer
1106
- define_model :person do
1107
- has_one :detail, class_name: 'PersonDetail'
1108
- end
1109
-
1110
- expect(Person.new).to have_one(:detail).class_name('PersonDetail')
1111
- end
1112
-
1113
- it 'rejects an association with a bad :class_name option' do
1114
- expect(having_one_detail).not_to have_one(:detail).class_name('NotSet')
1115
- end
1116
-
1117
- it 'rejects an association with non-existent implicit class name' do
1118
- expect(having_one_non_existent(:pserson, :detail)).not_to have_one(:detail)
1119
- end
1120
-
1121
- it 'rejects an association with non-existent explicit class name' do
1122
- expect(having_one_non_existent(:person, :detail, class_name: 'Detail')).not_to have_one(:detail)
1123
- end
1124
-
1125
- it 'adds error message when rejecting an association with non-existent class' do
1126
- message = 'Expected Person to have a has_one association called detail (Detail2 does not exist)'
1127
- expect {
1128
- expect(having_one_non_existent(:person, :detail, class_name: 'Detail2')).to have_one(:detail)
1129
- }.to fail_with_message(message)
1130
- end
1131
-
1132
- it 'accepts an association with a namespaced class name' do
1133
- define_module 'Models'
1134
- define_model 'Models::Account', user_id: :integer
1135
- user_model = define_model 'Models::User' do
1136
- has_one :account, class_name: 'Account'
1137
- end
1138
-
1139
- expect(user_model.new).
1140
- to have_one(:account).
1141
- class_name('Account')
1142
- end
1143
-
1144
- it 'resolves class_name within the context of the namespace before the global namespace' do
1145
- define_module 'Models'
1146
- define_model 'Account'
1147
- define_model 'Models::Account', user_id: :integer
1148
- user_model = define_model 'Models::User' do
1149
- has_one :account, class_name: 'Account'
1150
- end
1151
-
1152
- expect(user_model.new).
1153
- to have_one(:account).
1154
- class_name('Account')
1155
- end
1156
-
1157
- it 'accepts an association with a matching :autosave option' do
1158
- define_model :detail, person_id: :integer, disabled: :boolean
1159
- define_model :person do
1160
- has_one :detail, autosave: true
1161
- end
1162
- expect(Person.new).to have_one(:detail).autosave(true)
1163
- end
1164
-
1165
- it 'rejects an association with a non-matching :autosave option with the correct message' do
1166
- define_model :detail, person_id: :integer, disabled: :boolean
1167
- define_model :person do
1168
- has_one :detail, autosave: false
1169
- end
1170
-
1171
- message = 'Expected Person to have a has_one association called detail (detail should have autosave set to true)'
1172
- expect {
1173
- expect(Person.new).to have_one(:detail).autosave(true)
1174
- }.to fail_with_message(message)
1175
- end
1176
-
1177
-
1178
- it 'accepts an association with a through' do
1179
- define_model :detail
1180
-
1181
- define_model :account do
1182
- has_one :detail
1183
- end
1184
-
1185
- define_model :person do
1186
- has_one :account
1187
- has_one :detail, through: :account
1188
- end
1189
-
1190
- expect(Person.new).to have_one(:detail).through(:account)
1191
- end
1192
-
1193
- it 'rejects an association with a bad through' do
1194
- expect(having_one_detail).not_to have_one(:detail).through(:account)
1195
- end
1196
-
1197
- context 'validate' do
1198
- it 'accepts when the :validate option matches' do
1199
- expect(having_one_detail(validate: false)).
1200
- to have_one(:detail).validate(false)
1201
- end
1202
-
1203
- it 'rejects when the :validate option does not match' do
1204
- expect(having_one_detail(validate: true)).
1205
- not_to have_one(:detail).validate(false)
1206
- end
1207
-
1208
- it 'assumes validate() means validate(true)' do
1209
- expect(having_one_detail(validate: false)).
1210
- not_to have_one(:detail).validate
1211
- end
1212
-
1213
- it 'matches validate(false) to having no validate option specified' do
1214
- expect(having_one_detail).to have_one(:detail).validate(false)
1215
- end
1216
- end
1217
-
1218
- if active_record_supports_optional_for_associations?
1219
- context 'given an association with a matching :required option' do
1220
- it 'passes' do
1221
- expect(having_one_detail(required: true)).
1222
- to have_one(:detail).required
1223
- end
1224
- end
1225
- end
1226
-
1227
- context 'given an association with a non-matching :required option' do
1228
- it 'fails with an appropriate message' do
1229
- assertion = lambda do
1230
- expect(having_one_detail(required: false)).
1231
- to have_one(:detail).required
1232
- end
1233
-
1234
- message =
1235
- 'Expected Person to have a has_one association called detail ' +
1236
- '(the association should have been defined with `required: true`, ' +
1237
- 'but was not)'
1238
-
1239
- expect(&assertion).to fail_with_message(message)
1240
- end
1241
- end
1242
-
1243
- def having_one_detail(options = {})
1244
- define_model :detail, person_id: :integer
1245
- define_model(:person).tap do |model|
1246
- if options.key?(:order)
1247
- order = options.delete(:order)
1248
- define_association_with_order(model, :has_one, :detail, order, options)
1249
- else
1250
- model.has_one :detail, options
1251
- end
1252
- end.new
1253
- end
1254
-
1255
- def having_one_non_existent(model_name, assoc_name, options = {})
1256
- define_model model_name do
1257
- has_one assoc_name, options
1258
- end.new
1259
- end
1260
- end
1261
-
1262
- context 'have_and_belong_to_many' do
1263
- it 'accepts a valid association' do
1264
- expect(having_and_belonging_to_many_relatives).
1265
- to have_and_belong_to_many(:relatives)
1266
- end
1267
-
1268
- it 'rejects a nonexistent association' do
1269
- define_model :relative
1270
- define_model :person
1271
- define_model :people_relative, id: false, person_id: :integer,
1272
- relative_id: :integer
1273
-
1274
- expect(Person.new).not_to have_and_belong_to_many(:relatives)
1275
- end
1276
-
1277
- it 'rejects an association with a nonexistent join table' do
1278
- define_model :relative
1279
- define_model :person do
1280
- has_and_belongs_to_many :relatives
1281
- end
1282
-
1283
- expected_failure_message = "join table people_relatives doesn't exist"
1284
-
1285
- expect do
1286
- expect(Person.new).to have_and_belong_to_many(:relatives)
1287
- end.to fail_with_message_including(expected_failure_message)
1288
- end
1289
-
1290
- it 'rejects an association with a join table with incorrect columns' do
1291
- define_model :relative
1292
- define_model :person do
1293
- has_and_belongs_to_many :relatives
1294
- end
1295
-
1296
- define_model :people_relative, id: false, some_crazy_id: :integer
1297
-
1298
- expect do
1299
- expect(Person.new).to have_and_belong_to_many(:relatives)
1300
- end.to fail_with_message_including('missing columns: person_id, relative_id')
1301
- end
1302
-
1303
- context 'when the association is declared with a :join_table option' do
1304
- it 'accepts when testing with the same :join_table option' do
1305
- join_table_name = 'people_and_their_families'
1306
-
1307
- define_model :relative
1308
-
1309
- define_model :person do
1310
- has_and_belongs_to_many(:relatives, join_table: join_table_name)
1311
- end
1312
-
1313
- create_table(join_table_name, id: false) do |t|
1314
- t.references :person
1315
- t.references :relative
1316
- end
1317
-
1318
- expect(Person.new).
1319
- to have_and_belong_to_many(:relatives).
1320
- join_table(join_table_name)
1321
- end
1322
-
1323
- it 'accepts even when not explicitly testing with a :join_table option' do
1324
- join_table_name = 'people_and_their_families'
1325
-
1326
- define_model :relative
1327
-
1328
- define_model :person do
1329
- has_and_belongs_to_many(:relatives,
1330
- join_table: join_table_name
1331
- )
1332
- end
1333
-
1334
- create_table(join_table_name, id: false) do |t|
1335
- t.references :person
1336
- t.references :relative
1337
- end
1338
-
1339
- expect(Person.new).to have_and_belong_to_many(:relatives)
1340
- end
1341
-
1342
- it 'rejects when testing with a different :join_table option' do
1343
- join_table_name = 'people_and_their_families'
1344
-
1345
- define_model :relative
1346
-
1347
- define_model :person do
1348
- has_and_belongs_to_many(
1349
- :relatives,
1350
- join_table: join_table_name
1351
- )
1352
- end
1353
-
1354
- create_table(join_table_name, id: false) do |t|
1355
- t.references :person
1356
- t.references :relative
1357
- end
1358
-
1359
- assertion = lambda do
1360
- expect(Person.new).
1361
- to have_and_belong_to_many(:relatives).
1362
- join_table('family_tree')
1363
- end
1364
-
1365
- expect(&assertion).to fail_with_message_including(
1366
- "relatives should use 'family_tree' for :join_table option"
1367
- )
1368
- end
1369
- end
1370
-
1371
- context 'when the association is not declared with a :join_table option' do
1372
- it 'rejects when testing with a :join_table option' do
1373
- define_model :relative
1374
-
1375
- define_model :person do
1376
- has_and_belongs_to_many(:relatives)
1377
- end
1378
-
1379
- create_table('people_relatives', id: false) do |t|
1380
- t.references :person
1381
- t.references :relative
1382
- end
1383
-
1384
- assertion = lambda do
1385
- expect(Person.new).
1386
- to have_and_belong_to_many(:relatives).
1387
- join_table('family_tree')
1388
- end
1389
-
1390
- expect(&assertion).to fail_with_message_including(
1391
- "relatives should use 'family_tree' for :join_table option"
1392
- )
1393
- end
1394
- end
1395
-
1396
- context 'using a custom foreign key' do
1397
- it 'rejects an association with a join table with incorrect columns' do
1398
- define_model :relative
1399
- define_model :person do
1400
- has_and_belongs_to_many :relatives,
1401
- foreign_key: :custom_foreign_key_id
1402
- end
1403
-
1404
- define_model :people_relative,
1405
- id: false,
1406
- custom_foreign_key_id: :integer,
1407
- some_crazy_id: :integer
1408
-
1409
- expect do
1410
- expect(Person.new).to have_and_belong_to_many(:relatives)
1411
- end.to fail_with_message_including('missing column: relative_id')
1412
- end
1413
- end
1414
-
1415
- context 'using a custom association foreign key' do
1416
- it 'rejects an association with a join table with incorrect columns' do
1417
- define_model :relative
1418
- define_model :person do
1419
- has_and_belongs_to_many :relatives,
1420
- association_foreign_key: :custom_association_foreign_key_id
1421
- end
1422
-
1423
- define_model :people_relative,
1424
- id: false,
1425
- custom_association_foreign_key_id: :integer,
1426
- some_crazy_id: :integer
1427
-
1428
- expect do
1429
- expect(Person.new).to have_and_belong_to_many(:relatives)
1430
- end.to fail_with_message_including('missing column: person_id')
1431
- end
1432
-
1433
- it 'accepts foreign keys when they are symbols' do
1434
- define_model :relative
1435
- define_model :person do
1436
- has_and_belongs_to_many :relatives,
1437
- foreign_key: :some_foreign_key_id,
1438
- association_foreign_key: :custom_association_foreign_key_id
1439
- end
1440
-
1441
- define_model :people_relative,
1442
- id: false,
1443
- custom_association_foreign_key_id: :integer,
1444
- some_foreign_key_id: :integer
1445
-
1446
- expect(Person.new).to have_and_belong_to_many(:relatives)
1447
-
1448
- end
1449
-
1450
- end
1451
-
1452
- it 'rejects an association of the wrong type' do
1453
- define_model :relative, person_id: :integer
1454
- define_model :person do
1455
- has_many :relatives
1456
- end
1457
-
1458
- expect(Person.new).not_to have_and_belong_to_many(:relatives)
1459
- end
1460
-
1461
- it 'accepts an association with a valid :conditions option' do
1462
- define_model :relative, adopted: :boolean
1463
- define_model(:person).tap do |model|
1464
- define_association_with_conditions(model, :has_and_belongs_to_many, :relatives, adopted: true)
1465
- end
1466
- define_model :people_relative, id: false, person_id: :integer,
1467
- relative_id: :integer
1468
-
1469
- expect(Person.new).to have_and_belong_to_many(:relatives).conditions(adopted: true)
1470
- end
1471
-
1472
- it 'rejects an association with a bad :conditions option' do
1473
- define_model :relative, adopted: :boolean
1474
- define_model :person do
1475
- has_and_belongs_to_many :relatives
1476
- end
1477
- define_model :people_relative, id: false, person_id: :integer,
1478
- relative_id: :integer
1479
-
1480
- expect(Person.new).not_to have_and_belong_to_many(:relatives).conditions(adopted: true)
1481
- end
1482
-
1483
- it 'accepts an association without a :class_name option' do
1484
- expect(having_and_belonging_to_many_relatives).
1485
- to have_and_belong_to_many(:relatives).class_name('Relative')
1486
- end
1487
-
1488
- it 'accepts an association with a valid :class_name option' do
1489
- define_model :person_relative, adopted: :boolean
1490
- define_model :person do
1491
- has_and_belongs_to_many :relatives, class_name: 'PersonRelative'
1492
- end
1493
-
1494
- define_model :people_person_relative, person_id: :integer,
1495
- person_relative_id: :integer
1496
-
1497
- expect(Person.new).to have_and_belong_to_many(:relatives).class_name('PersonRelative')
1498
- end
1499
-
1500
- it 'rejects an association with a bad :class_name option' do
1501
- expect(having_and_belonging_to_many_relatives).
1502
- not_to have_and_belong_to_many(:relatives).class_name('PersonRelatives')
1503
- end
1504
-
1505
- it 'rejects an association with non-existent implicit class name' do
1506
- expect(having_and_belonging_to_many_non_existent_class(:person, :relatives)).
1507
- not_to have_and_belong_to_many(:relatives)
1508
- end
1509
-
1510
- it 'rejects an association with non-existent explicit class name' do
1511
- expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative')).
1512
- not_to have_and_belong_to_many(:relatives)
1513
- end
1514
-
1515
- it 'adds error message when rejecting an association with non-existent class' do
1516
- message = 'Expected Person to have a has_and_belongs_to_many association called relatives (Relative2 does not exist)'
1517
- expect {
1518
- expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative2')).
1519
- to have_and_belong_to_many(:relatives)
1520
- }.to fail_with_message(message)
1521
- end
1522
-
1523
- it 'accepts an association with a namespaced class name' do
1524
- possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users]
1525
- possible_join_table_names.each do |join_table_name|
1526
- create_table join_table_name, id: false do |t|
1527
- t.integer :group_id
1528
- t.integer :user_id
1529
- end
1530
- end
1531
- define_module 'Models'
1532
- define_model 'Models::Group'
1533
- user_model = define_model 'Models::User' do
1534
- has_and_belongs_to_many :groups, class_name: 'Group'
1535
- end
1536
-
1537
- expect(user_model.new).
1538
- to have_and_belong_to_many(:groups).
1539
- class_name('Group')
1540
- end
1541
-
1542
- it 'resolves class_name within the context of the namespace before the global namespace' do
1543
- possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users]
1544
- possible_join_table_names.each do |join_table_name|
1545
- create_table join_table_name, id: false do |t|
1546
- t.integer :group_id
1547
- t.integer :user_id
1548
- end
1549
- end
1550
- define_module 'Models'
1551
- define_model 'Group'
1552
- define_model 'Models::Group'
1553
- user_model = define_model 'Models::User' do
1554
- has_and_belongs_to_many :groups, class_name: 'Group'
1555
- end
1556
-
1557
- expect(user_model.new).
1558
- to have_and_belong_to_many(:groups).
1559
- class_name('Group')
1560
- end
1561
-
1562
- it 'accepts an association with a matching :autosave option' do
1563
- define_model :relatives, adopted: :boolean
1564
- define_model :person do
1565
- has_and_belongs_to_many :relatives, autosave: true
1566
- end
1567
- define_model :people_relative, person_id: :integer,
1568
- relative_id: :integer
1569
- expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
1570
- end
1571
-
1572
- it 'rejects an association with a non-matching :autosave option with the correct message' do
1573
- define_model :relatives, adopted: :boolean
1574
- define_model :person do
1575
- has_and_belongs_to_many :relatives
1576
- end
1577
- define_model :people_relative, person_id: :integer,
1578
- relative_id: :integer
1579
-
1580
- message = 'Expected Person to have a has_and_belongs_to_many association called relatives (relatives should have autosave set to true)'
1581
- expect {
1582
- expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
1583
- }.to fail_with_message(message)
1584
- end
1585
-
1586
- context 'validate' do
1587
- it 'accepts when the :validate option matches' do
1588
- expect(having_and_belonging_to_many_relatives(validate: false)).
1589
- to have_and_belong_to_many(:relatives).validate(false)
1590
- end
1591
-
1592
- it 'rejects when the :validate option does not match' do
1593
- expect(having_and_belonging_to_many_relatives(validate: true)).
1594
- to have_and_belong_to_many(:relatives).validate(false)
1595
- end
1596
-
1597
- it 'assumes validate() means validate(true)' do
1598
- expect(having_and_belonging_to_many_relatives(validate: false)).
1599
- not_to have_and_belong_to_many(:relatives).validate
1600
- end
1601
-
1602
- it 'matches validate(false) to having no validate option specified' do
1603
- expect(having_and_belonging_to_many_relatives).
1604
- to have_and_belong_to_many(:relatives).validate(false)
1605
- end
1606
- end
1607
-
1608
- def having_and_belonging_to_many_relatives(options = {})
1609
- define_model :relative
1610
- define_model :people_relative, id: false, person_id: :integer,
1611
- relative_id: :integer
1612
- define_model :person do
1613
- has_and_belongs_to_many :relatives
1614
- end.new
1615
- end
1616
-
1617
- def having_and_belonging_to_many_non_existent_class(model_name, assoc_name, options = {})
1618
- define_model model_name do
1619
- has_and_belongs_to_many assoc_name, options
1620
- end.new
1621
- end
1622
- end
1623
-
1624
- def define_association_with_conditions(model, macro, name, conditions, other_options={})
1625
- args = []
1626
- options = {}
1627
- if active_record_supports_relations?
1628
- args << proc { where(conditions) }
1629
- else
1630
- options[:conditions] = conditions
1631
- end
1632
- args << options
1633
- model.__send__(macro, name, *args)
1634
- end
1635
-
1636
- def define_association_with_order(model, macro, name, order, other_options={})
1637
- args = []
1638
- options = {}
1639
- if active_record_supports_relations?
1640
- args << proc { order(order) }
1641
- else
1642
- options[:order] = order
1643
- end
1644
- args << options
1645
- model.__send__(macro, name, *args)
1646
- end
1647
-
1648
- def dependent_options
1649
- if active_record_supports_more_dependent_options?
1650
- [:destroy, :delete, :nullify, :restrict_with_exception, :restrict_with_error]
1651
- else
1652
- [:destroy, :delete, :nullify, :restrict]
1653
- end
1654
- end
1655
-
1656
- def configuring_default_belongs_to_requiredness(value, &block)
1657
- configuring_application(
1658
- ActiveRecord::Base,
1659
- :belongs_to_required_by_default,
1660
- value,
1661
- &block
1662
- )
1663
- end
1664
-
1665
- def configuring_application(config, name, value)
1666
- previous_value = config.send(name)
1667
- config.send("#{name}=", value)
1668
- yield
1669
- ensure
1670
- config.send("#{name}=", previous_value)
1671
- end
1672
- end