shoulda-matchers 3.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. checksums.yaml +5 -5
  2. data/{MIT-LICENSE → LICENSE} +1 -1
  3. data/README.md +407 -232
  4. data/docs/errors/NonCaseSwappableValueError.md +2 -2
  5. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +7 -80
  6. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +4 -3
  7. data/lib/shoulda/matchers/action_controller/flash_store.rb +2 -4
  8. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +36 -30
  9. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +8 -10
  10. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +7 -9
  11. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +18 -15
  12. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +3 -2
  13. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +3 -3
  14. data/lib/shoulda/matchers/action_controller/route_matcher.rb +88 -29
  15. data/lib/shoulda/matchers/action_controller/route_params.rb +2 -2
  16. data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +4 -4
  17. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -3
  18. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
  19. data/lib/shoulda/matchers/action_controller.rb +2 -0
  20. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
  21. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -9
  22. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
  23. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
  24. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
  25. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +42 -39
  26. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
  27. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +52 -26
  28. data/lib/shoulda/matchers/active_model/helpers.rb +2 -2
  29. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -30
  30. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +2 -1
  31. data/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
  32. data/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
  33. data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
  34. data/lib/shoulda/matchers/active_model/qualifiers.rb +2 -0
  35. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -6
  36. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +8 -3
  37. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +31 -16
  38. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +52 -16
  39. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +137 -84
  40. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +159 -46
  41. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +130 -66
  42. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +251 -24
  43. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +12 -9
  44. data/lib/shoulda/matchers/active_model/validation_matcher.rb +38 -6
  45. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
  46. data/lib/shoulda/matchers/active_model/validator.rb +4 -9
  47. data/lib/shoulda/matchers/active_model.rb +3 -5
  48. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +10 -7
  49. data/lib/shoulda/matchers/active_record/association_matcher.rb +386 -111
  50. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
  51. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
  52. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
  53. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
  54. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +14 -15
  55. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +30 -8
  56. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +34 -11
  57. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +69 -0
  58. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
  59. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +74 -0
  60. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
  61. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
  62. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +458 -42
  63. data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +185 -0
  64. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +63 -23
  65. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +164 -48
  66. data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +106 -0
  67. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +13 -11
  68. data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
  69. data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
  70. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +18 -18
  71. data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
  72. data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
  73. data/lib/shoulda/matchers/active_record/uniqueness.rb +1 -1
  74. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +430 -200
  75. data/lib/shoulda/matchers/active_record.rb +28 -20
  76. data/lib/shoulda/matchers/configuration.rb +12 -1
  77. data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
  78. data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
  79. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
  80. data/lib/shoulda/matchers/doublespeak/object_double.rb +6 -2
  81. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
  82. data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
  83. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  84. data/lib/shoulda/matchers/error.rb +1 -1
  85. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +109 -29
  86. data/lib/shoulda/matchers/independent.rb +2 -2
  87. data/lib/shoulda/matchers/integrations/configuration.rb +8 -4
  88. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
  89. data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
  90. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
  91. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
  92. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
  93. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
  94. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
  95. data/lib/shoulda/matchers/rails_shim.rb +172 -51
  96. data/lib/shoulda/matchers/routing.rb +2 -2
  97. data/lib/shoulda/matchers/util/word_wrap.rb +17 -12
  98. data/lib/shoulda/matchers/util.rb +39 -5
  99. data/lib/shoulda/matchers/version.rb +1 -1
  100. data/lib/shoulda/matchers/warn.rb +4 -3
  101. data/shoulda-matchers.gemspec +33 -15
  102. metadata +31 -338
  103. data/.gitignore +0 -12
  104. data/.hound.yml +0 -3
  105. data/.hound_config/ruby.yml +0 -12
  106. data/.travis.yml +0 -19
  107. data/.yardopts +0 -10
  108. data/Appraisals +0 -73
  109. data/CONTRIBUTING.md +0 -101
  110. data/Gemfile +0 -15
  111. data/Gemfile.lock +0 -70
  112. data/NEWS.md +0 -986
  113. data/Rakefile +0 -39
  114. data/custom_plan.rb +0 -88
  115. data/doc_config/gh-pages/index.html.erb +0 -9
  116. data/doc_config/yard/setup.rb +0 -22
  117. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -5967
  118. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +0 -12
  119. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +0 -62
  120. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +0 -69
  121. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +0 -312
  122. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -32
  123. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +0 -1
  124. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +0 -8
  125. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -298
  126. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +0 -1
  127. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +0 -289
  128. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +0 -6
  129. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +0 -8
  130. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +0 -14
  131. data/doc_config/yard/templates/default/layout/html/fonts.erb +0 -1
  132. data/doc_config/yard/templates/default/layout/html/footer.erb +0 -6
  133. data/doc_config/yard/templates/default/layout/html/layout.erb +0 -23
  134. data/doc_config/yard/templates/default/layout/html/search.erb +0 -13
  135. data/doc_config/yard/templates/default/layout/html/setup.rb +0 -40
  136. data/doc_config/yard/templates/default/method_details/html/source.erb +0 -10
  137. data/doc_config/yard/templates/default/module/html/box_info.erb +0 -31
  138. data/gemfiles/4.0.0.gemfile +0 -38
  139. data/gemfiles/4.0.0.gemfile.lock +0 -223
  140. data/gemfiles/4.0.1.gemfile +0 -38
  141. data/gemfiles/4.0.1.gemfile.lock +0 -225
  142. data/gemfiles/4.1.gemfile +0 -38
  143. data/gemfiles/4.1.gemfile.lock +0 -220
  144. data/gemfiles/4.2.gemfile +0 -38
  145. data/gemfiles/4.2.gemfile.lock +0 -243
  146. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +0 -159
  147. data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +0 -37
  148. data/script/SUPPORTED_VERSIONS +0 -1
  149. data/script/install_gems_in_all_appraisals +0 -14
  150. data/script/run_all_tests +0 -14
  151. data/script/update_gem_in_all_appraisals +0 -15
  152. data/script/update_gems_in_all_appraisals +0 -14
  153. data/spec/acceptance/active_model_integration_spec.rb +0 -23
  154. data/spec/acceptance/independent_matchers_spec.rb +0 -125
  155. data/spec/acceptance/multiple_libraries_integration_spec.rb +0 -55
  156. data/spec/acceptance/rails_integration_spec.rb +0 -156
  157. data/spec/acceptance_spec_helper.rb +0 -23
  158. data/spec/doublespeak_spec_helper.rb +0 -2
  159. data/spec/report_warnings.rb +0 -7
  160. data/spec/spec_helper.rb +0 -21
  161. data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +0 -133
  162. data/spec/support/acceptance/helpers/active_model_helpers.rb +0 -11
  163. data/spec/support/acceptance/helpers/array_helpers.rb +0 -13
  164. data/spec/support/acceptance/helpers/base_helpers.rb +0 -19
  165. data/spec/support/acceptance/helpers/command_helpers.rb +0 -55
  166. data/spec/support/acceptance/helpers/file_helpers.rb +0 -19
  167. data/spec/support/acceptance/helpers/gem_helpers.rb +0 -31
  168. data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -11
  169. data/spec/support/acceptance/helpers/n_unit_helpers.rb +0 -25
  170. data/spec/support/acceptance/helpers/pluralization_helpers.rb +0 -13
  171. data/spec/support/acceptance/helpers/rails_version_helpers.rb +0 -11
  172. data/spec/support/acceptance/helpers/rspec_helpers.rb +0 -24
  173. data/spec/support/acceptance/helpers/ruby_version_helpers.rb +0 -9
  174. data/spec/support/acceptance/helpers/step_helpers.rb +0 -127
  175. data/spec/support/acceptance/helpers.rb +0 -31
  176. data/spec/support/acceptance/matchers/have_output.rb +0 -31
  177. data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +0 -55
  178. data/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +0 -103
  179. data/spec/support/tests/bundle.rb +0 -94
  180. data/spec/support/tests/command_runner.rb +0 -230
  181. data/spec/support/tests/current_bundle.rb +0 -61
  182. data/spec/support/tests/database.rb +0 -28
  183. data/spec/support/tests/database_adapters/postgresql.rb +0 -25
  184. data/spec/support/tests/database_adapters/sqlite3.rb +0 -26
  185. data/spec/support/tests/database_configuration.rb +0 -33
  186. data/spec/support/tests/database_configuration_registry.rb +0 -28
  187. data/spec/support/tests/filesystem.rb +0 -100
  188. data/spec/support/tests/version.rb +0 -45
  189. data/spec/support/unit/active_record/create_table.rb +0 -54
  190. data/spec/support/unit/attribute.rb +0 -47
  191. data/spec/support/unit/capture.rb +0 -40
  192. data/spec/support/unit/change_value.rb +0 -111
  193. data/spec/support/unit/create_model_arguments/basic.rb +0 -135
  194. data/spec/support/unit/create_model_arguments/has_many.rb +0 -15
  195. data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +0 -74
  196. data/spec/support/unit/helpers/active_model_helpers.rb +0 -27
  197. data/spec/support/unit/helpers/active_model_versions.rb +0 -28
  198. data/spec/support/unit/helpers/active_record_versions.rb +0 -24
  199. data/spec/support/unit/helpers/active_resource_builder.rb +0 -27
  200. data/spec/support/unit/helpers/allow_value_matcher_helpers.rb +0 -15
  201. data/spec/support/unit/helpers/class_builder.rb +0 -90
  202. data/spec/support/unit/helpers/column_type_helpers.rb +0 -26
  203. data/spec/support/unit/helpers/confirmation_matcher_helpers.rb +0 -17
  204. data/spec/support/unit/helpers/controller_builder.rb +0 -63
  205. data/spec/support/unit/helpers/database_helpers.rb +0 -20
  206. data/spec/support/unit/helpers/i18n_faker.rb +0 -15
  207. data/spec/support/unit/helpers/mailer_builder.rb +0 -12
  208. data/spec/support/unit/helpers/model_builder.rb +0 -114
  209. data/spec/support/unit/helpers/rails_versions.rb +0 -28
  210. data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +0 -44
  211. data/spec/support/unit/i18n.rb +0 -7
  212. data/spec/support/unit/load_environment.rb +0 -12
  213. data/spec/support/unit/matchers/deprecate.rb +0 -60
  214. data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +0 -51
  215. data/spec/support/unit/matchers/fail_with_message_matcher.rb +0 -62
  216. data/spec/support/unit/matchers/print_warning_including.rb +0 -59
  217. data/spec/support/unit/model_creation_strategies/active_model.rb +0 -111
  218. data/spec/support/unit/model_creation_strategies/active_record.rb +0 -77
  219. data/spec/support/unit/model_creators/active_model.rb +0 -39
  220. data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +0 -95
  221. data/spec/support/unit/model_creators/active_record/has_many.rb +0 -67
  222. data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +0 -42
  223. data/spec/support/unit/model_creators/active_record.rb +0 -43
  224. data/spec/support/unit/model_creators/basic.rb +0 -97
  225. data/spec/support/unit/model_creators.rb +0 -19
  226. data/spec/support/unit/rails_application.rb +0 -126
  227. data/spec/support/unit/record_builder_with_i18n_validation_message.rb +0 -69
  228. data/spec/support/unit/record_validating_confirmation_builder.rb +0 -51
  229. data/spec/support/unit/record_with_different_error_attribute_builder.rb +0 -92
  230. data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +0 -79
  231. data/spec/support/unit/shared_examples/numerical_submatcher.rb +0 -17
  232. data/spec/support/unit/shared_examples/set_session_or_flash.rb +0 -360
  233. data/spec/support/unit/validation_matcher_scenario.rb +0 -62
  234. data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +0 -82
  235. data/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +0 -28
  236. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +0 -592
  237. data/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +0 -42
  238. data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +0 -76
  239. data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +0 -62
  240. data/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +0 -90
  241. data/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +0 -31
  242. data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +0 -330
  243. data/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb +0 -30
  244. data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +0 -67
  245. data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +0 -17
  246. data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +0 -562
  247. data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -115
  248. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +0 -823
  249. data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -86
  250. data/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +0 -20
  251. data/spec/unit/shoulda/matchers/active_model/helpers_spec.rb +0 -162
  252. data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +0 -266
  253. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +0 -91
  254. data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +0 -149
  255. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -207
  256. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -1015
  257. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -288
  258. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +0 -1837
  259. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -380
  260. data/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -107
  261. data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +0 -1242
  262. data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +0 -251
  263. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +0 -168
  264. data/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +0 -111
  265. data/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +0 -85
  266. data/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +0 -41
  267. data/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +0 -86
  268. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +0 -1418
  269. data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +0 -190
  270. data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +0 -21
  271. data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +0 -271
  272. data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +0 -77
  273. data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +0 -72
  274. data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +0 -101
  275. data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +0 -80
  276. data/spec/unit/shoulda/matchers/doublespeak_spec.rb +0 -27
  277. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb +0 -43
  278. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +0 -517
  279. data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +0 -242
  280. data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +0 -252
  281. data/spec/unit_spec_helper.rb +0 -46
  282. data/spec/warnings_spy/filesystem.rb +0 -45
  283. data/spec/warnings_spy/partitioner.rb +0 -36
  284. data/spec/warnings_spy/reader.rb +0 -53
  285. data/spec/warnings_spy/reporter.rb +0 -88
  286. data/spec/warnings_spy.rb +0 -64
  287. data/tasks/documentation.rb +0 -199
  288. data/zeus.json +0 -11
@@ -1,1242 +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_parent(inverse_of: :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_parent(inverse_of: :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
- def belonging_to_parent(options = {})
283
- define_model :parent
284
- define_model :child, parent_id: :integer do
285
- belongs_to :parent, options
286
- end.new
287
- end
288
-
289
- def belonging_to_non_existent_class(model_name, assoc_name, options = {})
290
- define_model model_name, "#{assoc_name}_id" => :integer do
291
- belongs_to assoc_name, options
292
- end.new
293
- end
294
- end
295
-
296
- context 'have_many' do
297
- it 'accepts a valid association without any options' do
298
- expect(having_many_children).to have_many(:children)
299
- end
300
-
301
- it 'accepts a valid association with a :through option' do
302
- define_model :child
303
- define_model :conception, child_id: :integer,
304
- parent_id: :integer do
305
- belongs_to :child
306
- end
307
- define_model :parent do
308
- has_many :conceptions
309
- has_many :children, through: :conceptions
310
- end
311
- expect(Parent.new).to have_many(:children)
312
- end
313
-
314
- it 'accepts a valid association with an :as option' do
315
- define_model :child, guardian_type: :string, guardian_id: :integer
316
- define_model :parent do
317
- has_many :children, as: :guardian
318
- end
319
-
320
- expect(Parent.new).to have_many(:children)
321
- end
322
-
323
- it 'rejects an association that has a nonexistent foreign key' do
324
- define_model :child
325
- define_model :parent do
326
- has_many :children
327
- end
328
-
329
- expect(Parent.new).not_to have_many(:children)
330
- end
331
-
332
- it 'accepts an association using an existing custom primary key' do
333
- define_model :child, parent_id: :integer
334
- define_model :parent, custom_primary_key: :integer do
335
- has_many :children, primary_key: :custom_primary_key
336
- end
337
- expect(Parent.new).to have_many(:children).with_primary_key(:custom_primary_key)
338
- end
339
-
340
- it 'rejects an association with a bad :primary_key option' do
341
- matcher = have_many(:children).with_primary_key(:custom_primary_key)
342
-
343
- expect(having_many_children).not_to matcher
344
-
345
- expect(matcher.failure_message).to match(/Parent does not have a custom_primary_key primary key/)
346
- end
347
-
348
- it 'rejects an association with a bad :as option' do
349
- define_model :child, caretaker_type: :string,
350
- caretaker_id: :integer
351
- define_model :parent do
352
- has_many :children, as: :guardian
353
- end
354
-
355
- expect(Parent.new).not_to have_many(:children)
356
- end
357
-
358
- it 'rejects an association that has a bad :through option' do
359
- matcher = have_many(:children).through(:conceptions)
360
-
361
- expect(matcher.matches?(having_many_children)).to eq false
362
-
363
- expect(matcher.failure_message).to match(/does not have any relationship to conceptions/)
364
- end
365
-
366
- it 'rejects an association that has the wrong :through option' do
367
- define_model :child
368
-
369
- define_model :conception, child_id: :integer,
370
- parent_id: :integer do
371
- belongs_to :child
372
- end
373
-
374
- define_model :parent do
375
- has_many :conceptions
376
- has_many :relationships
377
- has_many :children, through: :conceptions
378
- end
379
-
380
- matcher = have_many(:children).through(:relationships)
381
- expect(matcher.matches?(Parent.new)).to eq false
382
- expect(matcher.failure_message).to match(/through relationships, but got it through conceptions/)
383
- end
384
-
385
- it 'produces a failure message without exception when association is missing :through option' do
386
- define_model :child
387
- define_model :parent
388
- matcher = have_many(:children).through(:relationships).source(:child)
389
- failure_message = 'Expected Parent to have a has_many association called children (no association called children)'
390
-
391
- matcher.matches?(Parent.new)
392
- expect(matcher.failure_message).to eq failure_message
393
- end
394
-
395
- it 'accepts an association with a valid :dependent option' do
396
- expect(having_many_children(dependent: :destroy)).
397
- to have_many(:children).dependent(:destroy)
398
- end
399
-
400
- it 'rejects an association with a bad :dependent option' do
401
- matcher = have_many(:children).dependent(:destroy)
402
-
403
- expect(having_many_children).not_to matcher
404
-
405
- expect(matcher.failure_message).to match(/children should have destroy dependency/)
406
- end
407
-
408
- it 'accepts an association with a valid :source option' do
409
- expect(having_many_children(source: :user)).
410
- to have_many(:children).source(:user)
411
- end
412
-
413
- it 'rejects an association with a bad :source option' do
414
- matcher = have_many(:children).source(:user)
415
-
416
- expect(having_many_children).not_to matcher
417
-
418
- expect(matcher.failure_message).to match(/children should have user as source option/)
419
- end
420
-
421
- it 'accepts an association with a valid :order option' do
422
- expect(having_many_children(order: :id)).
423
- to have_many(:children).order(:id)
424
- end
425
-
426
- it 'rejects an association with a bad :order option' do
427
- matcher = have_many(:children).order(:id)
428
-
429
- expect(having_many_children).not_to matcher
430
-
431
- expect(matcher.failure_message).to match(/children should be ordered by id/)
432
- end
433
-
434
- it 'accepts an association with a valid :conditions option' do
435
- define_model :child, parent_id: :integer, adopted: :boolean
436
- define_model(:parent).tap do |model|
437
- define_association_with_conditions(model, :has_many, :children, adopted: true)
438
- end
439
-
440
- expect(Parent.new).to have_many(:children).conditions(adopted: true)
441
- end
442
-
443
- it 'rejects an association with a bad :conditions option' do
444
- define_model :child, parent_id: :integer, adopted: :boolean
445
- define_model :parent do
446
- has_many :children
447
- end
448
-
449
- expect(Parent.new).not_to have_many(:children).conditions(adopted: true)
450
- end
451
-
452
- it 'accepts an association without a :class_name option' do
453
- expect(having_many_children).to have_many(:children).class_name('Child')
454
- end
455
-
456
- it 'accepts an association with a valid :class_name option' do
457
- define_model :node, parent_id: :integer
458
- define_model :parent do
459
- has_many :children, class_name: 'Node'
460
- end
461
-
462
- expect(Parent.new).to have_many(:children).class_name('Node')
463
- end
464
-
465
- it 'rejects an association with a bad :class_name option' do
466
- expect(having_many_children).not_to have_many(:children).class_name('Node')
467
- end
468
-
469
- it 'rejects an association with non-existent implicit class name' do
470
- expect(having_many_non_existent_class(:parent, :children)).not_to have_many(:children)
471
- end
472
-
473
- it 'rejects an association with non-existent explicit class name' do
474
- expect(having_many_non_existent_class(:parent, :children, class_name: 'Child')).not_to have_many(:children)
475
- end
476
-
477
- it 'adds error message when rejecting an association with non-existent class' do
478
- message = 'Expected Parent to have a has_many association called children (Child2 does not exist)'
479
- expect {
480
- expect(having_many_non_existent_class(:parent, :children, class_name: 'Child2')).to have_many(:children)
481
- }.to fail_with_message(message)
482
- end
483
-
484
- it 'accepts an association with a namespaced class name' do
485
- define_module 'Models'
486
- define_model 'Models::Friend', user_id: :integer
487
- friend_model = define_model 'Models::User' do
488
- has_many :friends, class_name: 'Friend'
489
- end
490
-
491
- expect(friend_model.new).
492
- to have_many(:friends).
493
- class_name('Friend')
494
- end
495
-
496
- it 'resolves class_name within the context of the namespace before the global namespace' do
497
- define_module 'Models'
498
- define_model 'Friend'
499
- define_model 'Models::Friend', user_id: :integer
500
- friend_model = define_model 'Models::User' do
501
- has_many :friends, class_name: 'Friend'
502
- end
503
-
504
- expect(friend_model.new).
505
- to have_many(:friends).
506
- class_name('Friend')
507
- end
508
-
509
- it 'accepts an association with a matching :autosave option' do
510
- define_model :child, parent_id: :integer
511
- define_model :parent do
512
- has_many :children, autosave: true
513
- end
514
- expect(Parent.new).to have_many(:children).autosave(true)
515
- end
516
-
517
- it 'rejects an association with a non-matching :autosave option with the correct message' do
518
- define_model :child, parent_id: :integer
519
- define_model :parent do
520
- has_many :children, autosave: false
521
- end
522
-
523
- message = 'Expected Parent to have a has_many association called children (children should have autosave set to true)'
524
- expect {
525
- expect(Parent.new).to have_many(:children).autosave(true)
526
- }.to fail_with_message(message)
527
- end
528
-
529
- context 'validate' do
530
- it 'accepts when the :validate option matches' do
531
- expect(having_many_children(validate: false)).to have_many(:children).validate(false)
532
- end
533
-
534
- it 'rejects when the :validate option does not match' do
535
- expect(having_many_children(validate: true)).not_to have_many(:children).validate(false)
536
- end
537
-
538
- it 'assumes validate() means validate(true)' do
539
- expect(having_many_children(validate: false)).not_to have_many(:children).validate
540
- end
541
-
542
- it 'matches validate(false) to having no validate option specified' do
543
- expect(having_many_children).to have_many(:children).validate(false)
544
- end
545
- end
546
-
547
- it 'accepts an association with a nonstandard reverse foreign key, using :inverse_of' do
548
- define_model :child, ancestor_id: :integer do
549
- belongs_to :ancestor, inverse_of: :children, class_name: :Parent
550
- end
551
-
552
- define_model :parent do
553
- has_many :children, inverse_of: :ancestor
554
- end
555
-
556
- expect(Parent.new).to have_many(:children)
557
- end
558
-
559
- it 'rejects an association with a nonstandard reverse foreign key, if :inverse_of is not correct' do
560
- define_model :child, mother_id: :integer do
561
- belongs_to :mother, inverse_of: :children, class_name: :Parent
562
- end
563
-
564
- define_model :parent do
565
- has_many :children, inverse_of: :ancestor
566
- end
567
-
568
- expect(Parent.new).not_to have_many(:children)
569
- end
570
-
571
- def having_many_children(options = {})
572
- define_model :child, parent_id: :integer
573
- define_model(:parent).tap do |model|
574
- if options.key?(:order)
575
- order = options.delete(:order)
576
- define_association_with_order(model, :has_many, :children, order, options)
577
- else
578
- model.has_many :children, options
579
- end
580
- end.new
581
- end
582
-
583
- def having_many_non_existent_class(model_name, assoc_name, options = {})
584
- define_model model_name do
585
- has_many assoc_name, options
586
- end.new
587
- end
588
- end
589
-
590
- context 'have_one' do
591
- it 'accepts a valid association without any options' do
592
- expect(having_one_detail).to have_one(:detail)
593
- end
594
-
595
- it 'accepts a valid association with an :as option' do
596
- define_model :detail, detailable_id: :integer,
597
- detailable_type: :string
598
- define_model :person do
599
- has_one :detail, as: :detailable
600
- end
601
-
602
- expect(Person.new).to have_one(:detail)
603
- end
604
-
605
- it 'rejects an association that has a nonexistent foreign key' do
606
- define_model :detail
607
- define_model :person do
608
- has_one :detail
609
- end
610
-
611
- expect(Person.new).not_to have_one(:detail)
612
- end
613
-
614
- it 'accepts an association with an existing custom foreign key' do
615
- define_model :detail, detailed_person_id: :integer
616
- define_model :person do
617
- has_one :detail, foreign_key: :detailed_person_id
618
- end
619
- expect(Person.new).to have_one(:detail).with_foreign_key(:detailed_person_id)
620
- end
621
-
622
- it 'accepts an association using an existing custom primary key' do
623
- define_model :detail, person_id: :integer
624
- define_model :person, custom_primary_key: :integer do
625
- has_one :detail, primary_key: :custom_primary_key
626
- end
627
- expect(Person.new).to have_one(:detail).with_primary_key(:custom_primary_key)
628
- end
629
-
630
- it 'rejects an association with a bad :primary_key option' do
631
- matcher = have_one(:detail).with_primary_key(:custom_primary_key)
632
-
633
- expect(having_one_detail).not_to matcher
634
-
635
- expect(matcher.failure_message).to match(/Person does not have a custom_primary_key primary key/)
636
- end
637
-
638
- it 'rejects an association with a bad :as option' do
639
- define_model :detail, detailable_id: :integer,
640
- detailable_type: :string
641
- define_model :person do
642
- has_one :detail, as: :describable
643
- end
644
-
645
- expect(Person.new).not_to have_one(:detail)
646
- end
647
-
648
- it 'accepts an association with a valid :dependent option' do
649
- dependent_options.each do |option|
650
- expect(having_one_detail(dependent: option)).
651
- to have_one(:detail).dependent(option)
652
- end
653
- end
654
-
655
- it 'accepts any dependent option if true' do
656
- dependent_options.each do |option|
657
- expect(having_one_detail(dependent: option)).
658
- to have_one(:detail).dependent(true)
659
- end
660
- end
661
-
662
- it 'rejects any dependent options if false' do
663
- dependent_options.each do |option|
664
- expect(having_one_detail(dependent: option)).
665
- to_not have_one(:detail).dependent(false)
666
- end
667
- end
668
-
669
- it 'accepts a nil dependent option if false' do
670
- expect(having_one_detail).to have_one(:detail).dependent(false)
671
- end
672
-
673
- it 'rejects an association with a bad :dependent option' do
674
- matcher = have_one(:detail).dependent(:destroy)
675
-
676
- expect(having_one_detail).not_to matcher
677
-
678
- expect(matcher.failure_message).to match(/detail should have destroy dependency/)
679
- end
680
-
681
- it 'accepts an association with a valid :order option' do
682
- expect(having_one_detail(order: :id)).to have_one(:detail).order(:id)
683
- end
684
-
685
- it 'rejects an association with a bad :order option' do
686
- matcher = have_one(:detail).order(:id)
687
-
688
- expect(having_one_detail).not_to matcher
689
-
690
- expect(matcher.failure_message).to match(/detail should be ordered by id/)
691
- end
692
-
693
- it 'accepts an association with a valid :conditions option' do
694
- define_model :detail, person_id: :integer, disabled: :boolean
695
- define_model(:person).tap do |model|
696
- define_association_with_conditions(model, :has_one, :detail, disabled: true)
697
- end
698
-
699
- expect(Person.new).to have_one(:detail).conditions(disabled: true)
700
- end
701
-
702
- it 'rejects an association with a bad :conditions option' do
703
- define_model :detail, person_id: :integer, disabled: :boolean
704
- define_model :person do
705
- has_one :detail
706
- end
707
-
708
- expect(Person.new).not_to have_one(:detail).conditions(disabled: true)
709
- end
710
-
711
- it 'accepts an association without a :class_name option' do
712
- expect(having_one_detail).to have_one(:detail).class_name('Detail')
713
- end
714
-
715
- it 'accepts an association with a valid :class_name option' do
716
- define_model :person_detail, person_id: :integer
717
- define_model :person do
718
- has_one :detail, class_name: 'PersonDetail'
719
- end
720
-
721
- expect(Person.new).to have_one(:detail).class_name('PersonDetail')
722
- end
723
-
724
- it 'rejects an association with a bad :class_name option' do
725
- expect(having_one_detail).not_to have_one(:detail).class_name('NotSet')
726
- end
727
-
728
- it 'rejects an association with non-existent implicit class name' do
729
- expect(having_one_non_existent(:pserson, :detail)).not_to have_one(:detail)
730
- end
731
-
732
- it 'rejects an association with non-existent explicit class name' do
733
- expect(having_one_non_existent(:person, :detail, class_name: 'Detail')).not_to have_one(:detail)
734
- end
735
-
736
- it 'adds error message when rejecting an association with non-existent class' do
737
- message = 'Expected Person to have a has_one association called detail (Detail2 does not exist)'
738
- expect {
739
- expect(having_one_non_existent(:person, :detail, class_name: 'Detail2')).to have_one(:detail)
740
- }.to fail_with_message(message)
741
- end
742
-
743
- it 'accepts an association with a namespaced class name' do
744
- define_module 'Models'
745
- define_model 'Models::Account', user_id: :integer
746
- user_model = define_model 'Models::User' do
747
- has_one :account, class_name: 'Account'
748
- end
749
-
750
- expect(user_model.new).
751
- to have_one(:account).
752
- class_name('Account')
753
- end
754
-
755
- it 'resolves class_name within the context of the namespace before the global namespace' do
756
- define_module 'Models'
757
- define_model 'Account'
758
- define_model 'Models::Account', user_id: :integer
759
- user_model = define_model 'Models::User' do
760
- has_one :account, class_name: 'Account'
761
- end
762
-
763
- expect(user_model.new).
764
- to have_one(:account).
765
- class_name('Account')
766
- end
767
-
768
- it 'accepts an association with a matching :autosave option' do
769
- define_model :detail, person_id: :integer, disabled: :boolean
770
- define_model :person do
771
- has_one :detail, autosave: true
772
- end
773
- expect(Person.new).to have_one(:detail).autosave(true)
774
- end
775
-
776
- it 'rejects an association with a non-matching :autosave option with the correct message' do
777
- define_model :detail, person_id: :integer, disabled: :boolean
778
- define_model :person do
779
- has_one :detail, autosave: false
780
- end
781
-
782
- message = 'Expected Person to have a has_one association called detail (detail should have autosave set to true)'
783
- expect {
784
- expect(Person.new).to have_one(:detail).autosave(true)
785
- }.to fail_with_message(message)
786
- end
787
-
788
-
789
- it 'accepts an association with a through' do
790
- define_model :detail
791
-
792
- define_model :account do
793
- has_one :detail
794
- end
795
-
796
- define_model :person do
797
- has_one :account
798
- has_one :detail, through: :account
799
- end
800
-
801
- expect(Person.new).to have_one(:detail).through(:account)
802
- end
803
-
804
- it 'rejects an association with a bad through' do
805
- expect(having_one_detail).not_to have_one(:detail).through(:account)
806
- end
807
-
808
- context 'validate' do
809
- it 'accepts when the :validate option matches' do
810
- expect(having_one_detail(validate: false)).
811
- to have_one(:detail).validate(false)
812
- end
813
-
814
- it 'rejects when the :validate option does not match' do
815
- expect(having_one_detail(validate: true)).
816
- not_to have_one(:detail).validate(false)
817
- end
818
-
819
- it 'assumes validate() means validate(true)' do
820
- expect(having_one_detail(validate: false)).
821
- not_to have_one(:detail).validate
822
- end
823
-
824
- it 'matches validate(false) to having no validate option specified' do
825
- expect(having_one_detail).to have_one(:detail).validate(false)
826
- end
827
- end
828
-
829
- def having_one_detail(options = {})
830
- define_model :detail, person_id: :integer
831
- define_model(:person).tap do |model|
832
- if options.key?(:order)
833
- order = options.delete(:order)
834
- define_association_with_order(model, :has_one, :detail, order, options)
835
- else
836
- model.has_one :detail, options
837
- end
838
- end.new
839
- end
840
-
841
- def having_one_non_existent(model_name, assoc_name, options = {})
842
- define_model model_name do
843
- has_one assoc_name, options
844
- end.new
845
- end
846
- end
847
-
848
- context 'have_and_belong_to_many' do
849
- it 'accepts a valid association' do
850
- expect(having_and_belonging_to_many_relatives).
851
- to have_and_belong_to_many(:relatives)
852
- end
853
-
854
- it 'rejects a nonexistent association' do
855
- define_model :relative
856
- define_model :person
857
- define_model :people_relative, id: false, person_id: :integer,
858
- relative_id: :integer
859
-
860
- expect(Person.new).not_to have_and_belong_to_many(:relatives)
861
- end
862
-
863
- it 'rejects an association with a nonexistent join table' do
864
- define_model :relative
865
- define_model :person do
866
- has_and_belongs_to_many :relatives
867
- end
868
-
869
- expected_failure_message = "join table people_relatives doesn't exist"
870
-
871
- expect do
872
- expect(Person.new).to have_and_belong_to_many(:relatives)
873
- end.to fail_with_message_including(expected_failure_message)
874
- end
875
-
876
- it 'rejects an association with a join table with incorrect columns' do
877
- define_model :relative
878
- define_model :person do
879
- has_and_belongs_to_many :relatives
880
- end
881
-
882
- define_model :people_relative, id: false, some_crazy_id: :integer
883
-
884
- expect do
885
- expect(Person.new).to have_and_belong_to_many(:relatives)
886
- end.to fail_with_message_including('missing columns: person_id, relative_id')
887
- end
888
-
889
- context 'when the association is declared with a :join_table option' do
890
- it 'accepts when testing with the same :join_table option' do
891
- join_table_name = 'people_and_their_families'
892
-
893
- define_model :relative
894
-
895
- define_model :person do
896
- has_and_belongs_to_many(:relatives, join_table: join_table_name)
897
- end
898
-
899
- create_table(join_table_name, id: false) do |t|
900
- t.references :person
901
- t.references :relative
902
- end
903
-
904
- expect(Person.new).
905
- to have_and_belong_to_many(:relatives).
906
- join_table(join_table_name)
907
- end
908
-
909
- it 'accepts even when not explicitly testing with a :join_table option' do
910
- join_table_name = 'people_and_their_families'
911
-
912
- define_model :relative
913
-
914
- define_model :person do
915
- has_and_belongs_to_many(:relatives,
916
- join_table: join_table_name
917
- )
918
- end
919
-
920
- create_table(join_table_name, id: false) do |t|
921
- t.references :person
922
- t.references :relative
923
- end
924
-
925
- expect(Person.new).to have_and_belong_to_many(:relatives)
926
- end
927
-
928
- it 'rejects when testing with a different :join_table option' do
929
- join_table_name = 'people_and_their_families'
930
-
931
- define_model :relative
932
-
933
- define_model :person do
934
- has_and_belongs_to_many(
935
- :relatives,
936
- join_table: join_table_name
937
- )
938
- end
939
-
940
- create_table(join_table_name, id: false) do |t|
941
- t.references :person
942
- t.references :relative
943
- end
944
-
945
- assertion = lambda do
946
- expect(Person.new).
947
- to have_and_belong_to_many(:relatives).
948
- join_table('family_tree')
949
- end
950
-
951
- expect(&assertion).to fail_with_message_including(
952
- "relatives should use 'family_tree' for :join_table option"
953
- )
954
- end
955
- end
956
-
957
- context 'when the association is not declared with a :join_table option' do
958
- it 'rejects when testing with a :join_table option' do
959
- define_model :relative
960
-
961
- define_model :person do
962
- has_and_belongs_to_many(:relatives)
963
- end
964
-
965
- create_table('people_relatives', id: false) do |t|
966
- t.references :person
967
- t.references :relative
968
- end
969
-
970
- assertion = lambda do
971
- expect(Person.new).
972
- to have_and_belong_to_many(:relatives).
973
- join_table('family_tree')
974
- end
975
-
976
- expect(&assertion).to fail_with_message_including(
977
- "relatives should use 'family_tree' for :join_table option"
978
- )
979
- end
980
- end
981
-
982
- context 'using a custom foreign key' do
983
- it 'rejects an association with a join table with incorrect columns' do
984
- define_model :relative
985
- define_model :person do
986
- has_and_belongs_to_many :relatives,
987
- foreign_key: :custom_foreign_key_id
988
- end
989
-
990
- define_model :people_relative,
991
- id: false,
992
- custom_foreign_key_id: :integer,
993
- some_crazy_id: :integer
994
-
995
- expect do
996
- expect(Person.new).to have_and_belong_to_many(:relatives)
997
- end.to fail_with_message_including('missing column: relative_id')
998
- end
999
- end
1000
-
1001
- context 'using a custom association foreign key' do
1002
- it 'rejects an association with a join table with incorrect columns' do
1003
- define_model :relative
1004
- define_model :person do
1005
- has_and_belongs_to_many :relatives,
1006
- association_foreign_key: :custom_association_foreign_key_id
1007
- end
1008
-
1009
- define_model :people_relative,
1010
- id: false,
1011
- custom_association_foreign_key_id: :integer,
1012
- some_crazy_id: :integer
1013
-
1014
- expect do
1015
- expect(Person.new).to have_and_belong_to_many(:relatives)
1016
- end.to fail_with_message_including('missing column: person_id')
1017
- end
1018
-
1019
- it 'accepts foreign keys when they are symbols' do
1020
- define_model :relative
1021
- define_model :person do
1022
- has_and_belongs_to_many :relatives,
1023
- foreign_key: :some_foreign_key_id,
1024
- association_foreign_key: :custom_association_foreign_key_id
1025
- end
1026
-
1027
- define_model :people_relative,
1028
- id: false,
1029
- custom_association_foreign_key_id: :integer,
1030
- some_foreign_key_id: :integer
1031
-
1032
- expect(Person.new).to have_and_belong_to_many(:relatives)
1033
-
1034
- end
1035
-
1036
- end
1037
-
1038
- it 'rejects an association of the wrong type' do
1039
- define_model :relative, person_id: :integer
1040
- define_model :person do
1041
- has_many :relatives
1042
- end
1043
-
1044
- expect(Person.new).not_to have_and_belong_to_many(:relatives)
1045
- end
1046
-
1047
- it 'accepts an association with a valid :conditions option' do
1048
- define_model :relative, adopted: :boolean
1049
- define_model(:person).tap do |model|
1050
- define_association_with_conditions(model, :has_and_belongs_to_many, :relatives, adopted: true)
1051
- end
1052
- define_model :people_relative, id: false, person_id: :integer,
1053
- relative_id: :integer
1054
-
1055
- expect(Person.new).to have_and_belong_to_many(:relatives).conditions(adopted: true)
1056
- end
1057
-
1058
- it 'rejects an association with a bad :conditions option' do
1059
- define_model :relative, adopted: :boolean
1060
- define_model :person do
1061
- has_and_belongs_to_many :relatives
1062
- end
1063
- define_model :people_relative, id: false, person_id: :integer,
1064
- relative_id: :integer
1065
-
1066
- expect(Person.new).not_to have_and_belong_to_many(:relatives).conditions(adopted: true)
1067
- end
1068
-
1069
- it 'accepts an association without a :class_name option' do
1070
- expect(having_and_belonging_to_many_relatives).
1071
- to have_and_belong_to_many(:relatives).class_name('Relative')
1072
- end
1073
-
1074
- it 'accepts an association with a valid :class_name option' do
1075
- define_model :person_relative, adopted: :boolean
1076
- define_model :person do
1077
- has_and_belongs_to_many :relatives, class_name: 'PersonRelative'
1078
- end
1079
-
1080
- define_model :people_person_relative, person_id: :integer,
1081
- person_relative_id: :integer
1082
-
1083
- expect(Person.new).to have_and_belong_to_many(:relatives).class_name('PersonRelative')
1084
- end
1085
-
1086
- it 'rejects an association with a bad :class_name option' do
1087
- expect(having_and_belonging_to_many_relatives).
1088
- not_to have_and_belong_to_many(:relatives).class_name('PersonRelatives')
1089
- end
1090
-
1091
- it 'rejects an association with non-existent implicit class name' do
1092
- expect(having_and_belonging_to_many_non_existent_class(:person, :relatives)).
1093
- not_to have_and_belong_to_many(:relatives)
1094
- end
1095
-
1096
- it 'rejects an association with non-existent explicit class name' do
1097
- expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative')).
1098
- not_to have_and_belong_to_many(:relatives)
1099
- end
1100
-
1101
- it 'adds error message when rejecting an association with non-existent class' do
1102
- message = 'Expected Person to have a has_and_belongs_to_many association called relatives (Relative2 does not exist)'
1103
- expect {
1104
- expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative2')).
1105
- to have_and_belong_to_many(:relatives)
1106
- }.to fail_with_message(message)
1107
- end
1108
-
1109
- it 'accepts an association with a namespaced class name' do
1110
- possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users]
1111
- possible_join_table_names.each do |join_table_name|
1112
- create_table join_table_name, id: false do |t|
1113
- t.integer :group_id
1114
- t.integer :user_id
1115
- end
1116
- end
1117
- define_module 'Models'
1118
- define_model 'Models::Group'
1119
- user_model = define_model 'Models::User' do
1120
- has_and_belongs_to_many :groups, class_name: 'Group'
1121
- end
1122
-
1123
- expect(user_model.new).
1124
- to have_and_belong_to_many(:groups).
1125
- class_name('Group')
1126
- end
1127
-
1128
- it 'resolves class_name within the context of the namespace before the global namespace' do
1129
- possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users]
1130
- possible_join_table_names.each do |join_table_name|
1131
- create_table join_table_name, id: false do |t|
1132
- t.integer :group_id
1133
- t.integer :user_id
1134
- end
1135
- end
1136
- define_module 'Models'
1137
- define_model 'Group'
1138
- define_model 'Models::Group'
1139
- user_model = define_model 'Models::User' do
1140
- has_and_belongs_to_many :groups, class_name: 'Group'
1141
- end
1142
-
1143
- expect(user_model.new).
1144
- to have_and_belong_to_many(:groups).
1145
- class_name('Group')
1146
- end
1147
-
1148
- it 'accepts an association with a matching :autosave option' do
1149
- define_model :relatives, adopted: :boolean
1150
- define_model :person do
1151
- has_and_belongs_to_many :relatives, autosave: true
1152
- end
1153
- define_model :people_relative, person_id: :integer,
1154
- relative_id: :integer
1155
- expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
1156
- end
1157
-
1158
- it 'rejects an association with a non-matching :autosave option with the correct message' do
1159
- define_model :relatives, adopted: :boolean
1160
- define_model :person do
1161
- has_and_belongs_to_many :relatives
1162
- end
1163
- define_model :people_relative, person_id: :integer,
1164
- relative_id: :integer
1165
-
1166
- message = 'Expected Person to have a has_and_belongs_to_many association called relatives (relatives should have autosave set to true)'
1167
- expect {
1168
- expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
1169
- }.to fail_with_message(message)
1170
- end
1171
-
1172
- context 'validate' do
1173
- it 'accepts when the :validate option matches' do
1174
- expect(having_and_belonging_to_many_relatives(validate: false)).
1175
- to have_and_belong_to_many(:relatives).validate(false)
1176
- end
1177
-
1178
- it 'rejects when the :validate option does not match' do
1179
- expect(having_and_belonging_to_many_relatives(validate: true)).
1180
- to have_and_belong_to_many(:relatives).validate(false)
1181
- end
1182
-
1183
- it 'assumes validate() means validate(true)' do
1184
- expect(having_and_belonging_to_many_relatives(validate: false)).
1185
- not_to have_and_belong_to_many(:relatives).validate
1186
- end
1187
-
1188
- it 'matches validate(false) to having no validate option specified' do
1189
- expect(having_and_belonging_to_many_relatives).
1190
- to have_and_belong_to_many(:relatives).validate(false)
1191
- end
1192
- end
1193
-
1194
- def having_and_belonging_to_many_relatives(options = {})
1195
- define_model :relative
1196
- define_model :people_relative, id: false, person_id: :integer,
1197
- relative_id: :integer
1198
- define_model :person do
1199
- has_and_belongs_to_many :relatives
1200
- end.new
1201
- end
1202
-
1203
- def having_and_belonging_to_many_non_existent_class(model_name, assoc_name, options = {})
1204
- define_model model_name do
1205
- has_and_belongs_to_many assoc_name, options
1206
- end.new
1207
- end
1208
- end
1209
-
1210
- def define_association_with_conditions(model, macro, name, conditions, other_options={})
1211
- args = []
1212
- options = {}
1213
- if Shoulda::Matchers::RailsShim.active_record_major_version == 4
1214
- args << proc { where(conditions) }
1215
- else
1216
- options[:conditions] = conditions
1217
- end
1218
- args << options
1219
- model.__send__(macro, name, *args)
1220
- end
1221
-
1222
- def define_association_with_order(model, macro, name, order, other_options={})
1223
- args = []
1224
- options = {}
1225
- if Shoulda::Matchers::RailsShim.active_record_major_version == 4
1226
- args << proc { order(order) }
1227
- else
1228
- options[:order] = order
1229
- end
1230
- args << options
1231
- model.__send__(macro, name, *args)
1232
- end
1233
-
1234
- def dependent_options
1235
- case Rails.version
1236
- when /\A3/
1237
- [:destroy, :delete, :nullify, :restrict]
1238
- when /\A4/
1239
- [:destroy, :delete, :nullify, :restrict_with_exception, :restrict_with_error]
1240
- end
1241
- end
1242
- end