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
@@ -12,7 +12,7 @@ module Shoulda
12
12
  # end
13
13
  #
14
14
  # # RSpec
15
- # describe Robot do
15
+ # RSpec.describe Robot, type: :model do
16
16
  # it { should validate_presence_of(:arms) }
17
17
  # end
18
18
  #
@@ -36,7 +36,7 @@ module Shoulda
36
36
  # validates_presence_of :password
37
37
  # end
38
38
  #
39
- # describe User do
39
+ # RSpec.describe User, type: :model do
40
40
  # subject { User.new(password: '123456') }
41
41
  #
42
42
  # it { should validate_presence_of(:password) }
@@ -57,6 +57,48 @@ module Shoulda
57
57
  #
58
58
  # #### Qualifiers
59
59
  #
60
+ # ##### allow_nil
61
+ #
62
+ # Use `allow_nil` if your model has an optional attribute.
63
+ #
64
+ # class Robot
65
+ # include ActiveModel::Model
66
+ # attr_accessor :nickname
67
+ #
68
+ # validates_presence_of :nickname, allow_nil: true
69
+ # end
70
+ #
71
+ # # RSpec
72
+ # RSpec.describe Robot, type: :model do
73
+ # it { should validate_presence_of(:nickname).allow_nil }
74
+ # end
75
+ #
76
+ # # Minitest (Shoulda)
77
+ # class RobotTest < ActiveSupport::TestCase
78
+ # should validate_presence_of(:nickname).allow_nil
79
+ # end
80
+ #
81
+ # #### allow_blank
82
+ #
83
+ # Use `allow_blank` to assert that the attribute allows blank.
84
+ #
85
+ # class Robot
86
+ # include ActiveModel::Model
87
+ # attr_accessor :nickname
88
+ #
89
+ # validates_presence_of :nickname, allow_blank: true
90
+ # end
91
+ #
92
+ # # RSpec
93
+ # RSpec.describe Robot, type: :model do
94
+ # it { should validate_presence_of(:nickname).allow_blank }
95
+ # end
96
+ #
97
+ # # Minitest (Shoulda)
98
+ # class RobotTest < ActiveSupport::TestCase
99
+ # should validate_presence_of(:nickname).allow_blank
100
+ # end
101
+ #
60
102
  # ##### on
61
103
  #
62
104
  # Use `on` if your validation applies only under a certain context.
@@ -69,7 +111,7 @@ module Shoulda
69
111
  # end
70
112
  #
71
113
  # # RSpec
72
- # describe Robot do
114
+ # RSpec.describe Robot, type: :model do
73
115
  # it { should validate_presence_of(:arms).on(:create) }
74
116
  # end
75
117
  #
@@ -90,7 +132,7 @@ module Shoulda
90
132
  # end
91
133
  #
92
134
  # # RSpec
93
- # describe Robot do
135
+ # RSpec.describe Robot, type: :model do
94
136
  # it do
95
137
  # should validate_presence_of(:legs).
96
138
  # with_message('Robot has no legs')
@@ -111,6 +153,9 @@ module Shoulda
111
153
 
112
154
  # @private
113
155
  class ValidatePresenceOfMatcher < ValidationMatcher
156
+ include Qualifiers::AllowNil
157
+ include Qualifiers::AllowBlank
158
+
114
159
  def initialize(attribute)
115
160
  super
116
161
  @expected_message = :blank
@@ -119,11 +164,41 @@ module Shoulda
119
164
  def matches?(subject)
120
165
  super(subject)
121
166
 
167
+ possibly_ignore_interference_by_writer
168
+
169
+ if secure_password_being_validated? &&
170
+ Shoulda::Matchers::RailsShim.active_model_lt_7?
171
+ ignore_interference_by_writer.default_to(when: :blank?)
172
+
173
+ disallowed_values.all? do |value|
174
+ disallows_and_double_checks_value_of!(value)
175
+ end
176
+ else
177
+ (!expects_to_allow_nil? || allows_value_of(nil)) &&
178
+ (!expects_to_allow_blank? || allows_value_of('')) &&
179
+ disallowed_values.all? do |value|
180
+ disallows_original_or_typecast_value?(value)
181
+ end
182
+ end
183
+ end
184
+
185
+ def does_not_match?(subject)
186
+ super(subject)
187
+
188
+ possibly_ignore_interference_by_writer
189
+
122
190
  if secure_password_being_validated?
123
191
  ignore_interference_by_writer.default_to(when: :blank?)
124
- disallows_and_double_checks_value_of!(blank_value, @expected_message)
192
+
193
+ disallowed_values.any? do |value|
194
+ allows_and_double_checks_value_of!(value)
195
+ end
125
196
  else
126
- disallows_original_or_typecast_value?(blank_value, @expected_message)
197
+ (expects_to_allow_nil? && disallows_value_of(nil)) ||
198
+ (expects_to_allow_blank? && disallows_value_of('')) ||
199
+ disallowed_values.any? do |value|
200
+ allows_original_or_typecast_value?(value)
201
+ end
127
202
  end
128
203
  end
129
204
 
@@ -131,43 +206,195 @@ module Shoulda
131
206
  "validate that :#{@attribute} cannot be empty/falsy"
132
207
  end
133
208
 
209
+ def failure_message
210
+ message = super
211
+
212
+ if should_add_footnote_about_belongs_to?
213
+ message << "\n\n"
214
+ message << Shoulda::Matchers.word_wrap(<<-MESSAGE.strip, indent: 2)
215
+ You're getting this error because #{reason_for_existing_presence_validation}.
216
+ *This* presence validation doesn't use "can't be blank", the usual validation
217
+ message, but "must exist" instead.
218
+
219
+ With that said, did you know that the `belong_to` matcher can test this
220
+ validation for you? Instead of using `validate_presence_of`, try
221
+ #{suggestions_for_belongs_to}
222
+ MESSAGE
223
+ end
224
+
225
+ message
226
+ end
227
+
134
228
  private
135
229
 
136
230
  def secure_password_being_validated?
137
- defined?(::ActiveModel::SecurePassword) &&
138
- @subject.class.ancestors.include?(::ActiveModel::SecurePassword::InstanceMethodsOnActivation) &&
139
- @attribute == :password
231
+ Shoulda::Matchers::RailsShim.digestible_attributes_in(@subject).
232
+ include?(@attribute)
140
233
  end
141
234
 
142
- def disallows_and_double_checks_value_of!(value, message)
143
- disallows_value_of(value, message)
235
+ def possibly_ignore_interference_by_writer
236
+ if secure_password_being_validated? && RailsShim.active_model_lt_7?
237
+ ignore_interference_by_writer.default_to(when: :blank?)
238
+ end
239
+ end
240
+
241
+ def allows_and_double_checks_value_of!(value)
242
+ allows_value_of(value, @expected_message)
243
+ rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError
244
+ raise ActiveModel::CouldNotSetPasswordError.create(model)
245
+ end
246
+
247
+ def allows_original_or_typecast_value?(value)
248
+ allows_value_of(value, @expected_message)
249
+ end
250
+
251
+ def disallows_and_double_checks_value_of!(value)
252
+ disallows_value_of(value, @expected_message)
144
253
  rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError
145
- raise ActiveModel::CouldNotSetPasswordError.create(@subject.class)
254
+ raise ActiveModel::CouldNotSetPasswordError.create(model)
255
+ end
256
+
257
+ def disallows_original_or_typecast_value?(value)
258
+ disallows_value_of(value, @expected_message)
259
+ end
260
+
261
+ def disallowed_values
262
+ if collection_association?
263
+ [Array.new]
264
+ elsif attachment?
265
+ [nil]
266
+ else
267
+ values = []
268
+
269
+ if attribute_accepts_string_values? && !expects_to_allow_blank?
270
+ values << ''
271
+ end
272
+
273
+ if !expects_to_allow_nil? && !expects_to_allow_blank?
274
+ values << nil
275
+ end
276
+
277
+ values
278
+ end
146
279
  end
147
280
 
148
- def disallows_original_or_typecast_value?(value, message)
149
- disallows_value_of(blank_value, @expected_message)
281
+ def should_add_footnote_about_belongs_to?
282
+ belongs_to_association_being_validated? &&
283
+ presence_validation_exists_on_attribute?
150
284
  end
151
285
 
152
- def blank_value
153
- if collection?
154
- []
286
+ def reason_for_existing_presence_validation
287
+ if belongs_to_association_configured_to_be_required?
288
+ "you've instructed your `belongs_to` association to add a "\
289
+ 'presence validation to the attribute'
155
290
  else
156
- nil
291
+ # assume ::ActiveRecord::Base.belongs_to_required_by_default == true
292
+ 'ActiveRecord is configured to add a presence validation to all '\
293
+ '`belongs_to` associations, and this includes yours'
157
294
  end
158
295
  end
159
296
 
160
- def collection?
161
- if reflection
162
- [:has_many, :has_and_belongs_to_many].include?(reflection.macro)
297
+ def suggestions_for_belongs_to
298
+ if belongs_to_association_configured_to_be_required?
299
+ <<~MESSAGE
300
+ one of the following instead, depending on your use case:
301
+
302
+ #{example_of_belongs_to(with: [:optional, false])}
303
+ #{example_of_belongs_to(with: [:required, true])}
304
+ MESSAGE
163
305
  else
306
+ <<~MESSAGE
307
+ the following instead:
308
+
309
+ #{example_of_belongs_to}
310
+ MESSAGE
311
+ end
312
+ end
313
+
314
+ def example_of_belongs_to(with: nil)
315
+ initial_call = "should belong_to(:#{association_name})"
316
+ inside =
317
+ if with
318
+ "#{initial_call}.#{with.first}(#{with.second})"
319
+ else
320
+ initial_call
321
+ end
322
+
323
+ if Shoulda::Matchers.integrations.test_frameworks.any?(&:n_unit?)
324
+ inside
325
+ else
326
+ "it { #{inside} }"
327
+ end
328
+ end
329
+
330
+ def belongs_to_association_configured_to_be_required?
331
+ association_options[:optional] == false ||
332
+ association_options[:required] == true
333
+ end
334
+
335
+ def belongs_to_association_being_validated?
336
+ association? && association_reflection.macro == :belongs_to
337
+ end
338
+
339
+ def attribute_accepts_string_values?
340
+ if association?
164
341
  false
342
+ elsif attribute_serialization_coder.respond_to?(:object_class)
343
+ attribute_serialization_coder.object_class == String
344
+ else
345
+ RailsShim.supports_full_attributes_api?(model) &&
346
+ attribute_type.try(:type) == :string
165
347
  end
166
348
  end
167
349
 
168
- def reflection
169
- @subject.class.respond_to?(:reflect_on_association) &&
170
- @subject.class.reflect_on_association(@attribute)
350
+ def association?
351
+ association_reflection.present?
352
+ end
353
+
354
+ def collection_association?
355
+ association? && [:has_many, :has_and_belongs_to_many].include?(
356
+ association_reflection.macro,
357
+ )
358
+ end
359
+
360
+ def attachment?
361
+ model_has_associations?(
362
+ ["#{@attribute}_attachment", "#{@attribute}_attachments"],
363
+ )
364
+ end
365
+
366
+ def association_name
367
+ association_reflection.name
368
+ end
369
+
370
+ def association_options
371
+ association_reflection&.options
372
+ end
373
+
374
+ def association_reflection
375
+ model.try(:reflect_on_association, @attribute)
376
+ end
377
+
378
+ def model_has_associations?(associations)
379
+ associations.any? do |association|
380
+ !!model.try(:reflect_on_association, association)
381
+ end
382
+ end
383
+
384
+ def attribute_serialization_coder
385
+ RailsShim.attribute_serialization_coder_for(model, @attribute)
386
+ end
387
+
388
+ def attribute_type
389
+ RailsShim.attribute_type_for(model, @attribute)
390
+ end
391
+
392
+ def presence_validation_exists_on_attribute?
393
+ model._validators.include?(@attribute)
394
+ end
395
+
396
+ def model
397
+ @subject.class
171
398
  end
172
399
  end
173
400
  end
@@ -15,11 +15,10 @@ module Shoulda
15
15
 
16
16
  def call
17
17
  if description_clauses_for_qualifiers.any?
18
- main_description +
19
- ', ' +
20
- description_clauses_for_qualifiers.to_sentence
18
+ "#{main_description}#{clause_for_allow_blank_or_nil},"\
19
+ " #{description_clauses_for_qualifiers.to_sentence}"
21
20
  else
22
- main_description
21
+ main_description + clause_for_allow_blank_or_nil
23
22
  end
24
23
  end
25
24
 
@@ -29,14 +28,18 @@ module Shoulda
29
28
 
30
29
  private
31
30
 
32
- def description_clauses_for_qualifiers
33
- description_clauses = []
34
-
31
+ def clause_for_allow_blank_or_nil
35
32
  if matcher.try(:expects_to_allow_blank?)
36
- description_clauses << 'but only if it is not blank'
33
+ ' as long as it is not blank'
37
34
  elsif matcher.try(:expects_to_allow_nil?)
38
- description_clauses << 'but only if it is not nil'
35
+ ' as long as it is not nil'
36
+ else
37
+ ''
39
38
  end
39
+ end
40
+
41
+ def description_clauses_for_qualifiers
42
+ description_clauses = []
40
43
 
41
44
  if matcher.try(:expects_strict?)
42
45
  description_clauses << 'raising a validation exception'
@@ -24,6 +24,11 @@ module Shoulda
24
24
  self
25
25
  end
26
26
 
27
+ def allow_blank
28
+ options[:allow_blank] = true
29
+ self
30
+ end
31
+
27
32
  def strict
28
33
  @expects_strict = true
29
34
  self
@@ -51,13 +56,18 @@ module Shoulda
51
56
  false
52
57
  end
53
58
 
59
+ def does_not_match?(subject)
60
+ @subject = subject
61
+ true
62
+ end
63
+
54
64
  def failure_message
55
65
  overall_failure_message.dup.tap do |message|
56
66
  if failure_reason.present?
57
67
  message << "\n"
58
68
  message << Shoulda::Matchers.word_wrap(
59
69
  failure_reason,
60
- indent: 2
70
+ indent: 2,
61
71
  )
62
72
  end
63
73
  end
@@ -65,11 +75,11 @@ module Shoulda
65
75
 
66
76
  def failure_message_when_negated
67
77
  overall_failure_message_when_negated.dup.tap do |message|
68
- if failure_reason_when_negated.present?
78
+ if failure_reason.present?
69
79
  message << "\n"
70
80
  message << Shoulda::Matchers.word_wrap(
71
- failure_reason_when_negated,
72
- indent: 2
81
+ failure_reason,
82
+ indent: 2,
73
83
  )
74
84
  end
75
85
  end
@@ -111,17 +121,31 @@ module Shoulda
111
121
  )
112
122
  end
113
123
 
124
+ def allow_blank_matches?
125
+ !expects_to_allow_blank? ||
126
+ blank_values.all? { |value| allows_value_of(value) }
127
+ end
128
+
129
+ def allow_blank_does_not_match?
130
+ expects_to_allow_blank? &&
131
+ blank_values.all? { |value| disallows_value_of(value) }
132
+ end
133
+
114
134
  private
115
135
 
136
+ attr_reader :options
137
+
116
138
  def overall_failure_message
117
139
  Shoulda::Matchers.word_wrap(
118
- "#{model.name} did not properly #{description}."
140
+ "Expected #{model.name} to #{description}, but this could not be "\
141
+ 'proved.',
119
142
  )
120
143
  end
121
144
 
122
145
  def overall_failure_message_when_negated
123
146
  Shoulda::Matchers.word_wrap(
124
- "Expected #{model.name} not to #{description}, but it did."
147
+ "Expected #{model.name} not to #{description}, but this could "\
148
+ 'not be proved.',
125
149
  )
126
150
  end
127
151
 
@@ -154,6 +178,14 @@ module Shoulda
154
178
  @last_submatcher_run = matcher
155
179
  matcher.matches?(subject)
156
180
  end
181
+
182
+ def expects_to_allow_blank?
183
+ options[:allow_blank]
184
+ end
185
+
186
+ def blank_values
187
+ ['', ' ', "\n", "\r", "\t", "\f"]
188
+ end
157
189
  end
158
190
  end
159
191
  end
@@ -5,7 +5,7 @@ module Shoulda
5
5
  class ValidationMessageFinder
6
6
  include Helpers
7
7
 
8
- def initialize(instance, attribute, context=nil)
8
+ def initialize(instance, attribute, context = nil)
9
9
  @instance = instance
10
10
  @attribute = attribute
11
11
  @context = context
@@ -50,7 +50,7 @@ module Shoulda
50
50
  end
51
51
 
52
52
  def validated_instance
53
- @validated_instance ||= validate_instance
53
+ @_validated_instance ||= validate_instance
54
54
  end
55
55
 
56
56
  def validate_instance
@@ -58,8 +58,6 @@ module Shoulda
58
58
  @instance
59
59
  end
60
60
  end
61
-
62
61
  end
63
62
  end
64
63
  end
65
-
@@ -98,24 +98,19 @@ module Shoulda
98
98
 
99
99
  all_validation_errors = record.errors.dup
100
100
 
101
- validation_error_messages =
102
- if record.errors.respond_to?(:[])
103
- record.errors[attribute]
104
- else
105
- record.errors.on(attribute)
106
- end
101
+ validation_error_messages = record.errors[attribute]
107
102
 
108
103
  {
109
104
  all_validation_errors: all_validation_errors,
110
105
  validation_error_messages: validation_error_messages,
111
- validation_exception_message: nil
106
+ validation_exception_message: nil,
112
107
  }
113
- rescue ::ActiveModel::StrictValidationFailed => exception
108
+ rescue ::ActiveModel::StrictValidationFailed => e
114
109
  @captured_validation_exception = true
115
110
  {
116
111
  all_validation_errors: nil,
117
112
  validation_error_messages: [],
118
- validation_exception_message: exception.message
113
+ validation_exception_message: e.message,
119
114
  }
120
115
  end
121
116
  end
@@ -26,15 +26,13 @@ require 'shoulda/matchers/active_model/numericality_matchers/comparison_matcher'
26
26
  require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher'
27
27
  require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher'
28
28
  require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher'
29
- require 'shoulda/matchers/active_model/allow_mass_assignment_of_matcher'
30
29
  require 'shoulda/matchers/active_model/errors'
31
30
  require 'shoulda/matchers/active_model/have_secure_password_matcher'
32
31
 
33
32
  module Shoulda
34
33
  module Matchers
35
- # This mixin provides matchers that are used to test behavior, such as
36
- # validations, that you've added to your ActiveModel (or ActiveRecord)
37
- # objects.
34
+ # This module provides matchers that are used to test behavior within
35
+ # ActiveModel or ActiveRecord classes.
38
36
  #
39
37
  # ### Testing conditional validations
40
38
  #
@@ -60,7 +58,7 @@ module Shoulda
60
58
  # end
61
59
  #
62
60
  # # RSpec
63
- # describe User do
61
+ # RSpec.describe User, type: :model do
64
62
  # context "when an admin" do
65
63
  # subject { User.new(admin: true) }
66
64
  #
@@ -9,7 +9,7 @@ module Shoulda
9
9
  # end
10
10
  #
11
11
  # # RSpec
12
- # describe Car do
12
+ # RSpec.describe Car, type: :model do
13
13
  # it { should accept_nested_attributes_for(:doors) }
14
14
  # end
15
15
  #
@@ -30,7 +30,7 @@ module Shoulda
30
30
  # end
31
31
  #
32
32
  # # RSpec
33
- # describe Car do
33
+ # RSpec.describe Car, type: :model do
34
34
  # it do
35
35
  # should accept_nested_attributes_for(:mirrors).
36
36
  # allow_destroy(true)
@@ -52,7 +52,7 @@ module Shoulda
52
52
  # end
53
53
  #
54
54
  # # RSpec
55
- # describe Car do
55
+ # RSpec.describe Car, type: :model do
56
56
  # it do
57
57
  # should accept_nested_attributes_for(:windows).
58
58
  # limit(3)
@@ -75,7 +75,7 @@ module Shoulda
75
75
  # end
76
76
  #
77
77
  # # RSpec
78
- # describe Car do
78
+ # RSpec.describe Car, type: :model do
79
79
  # it do
80
80
  # should accept_nested_attributes_for(:engine).
81
81
  # update_only(true)
@@ -158,17 +158,20 @@ module Shoulda
158
158
  end
159
159
 
160
160
  def allow_destroy_correct?
161
- failure_message = "#{should_or_should_not(@options[:allow_destroy])} allow destroy"
161
+ failure_message = "#{should_or_should_not(@options[:allow_destroy])}"\
162
+ ' allow destroy'
162
163
  verify_option_is_correct(:allow_destroy, failure_message)
163
164
  end
164
165
 
165
166
  def limit_correct?
166
- failure_message = "limit should be #{@options[:limit]}, got #{config[:limit]}"
167
+ failure_message = "limit should be #{@options[:limit]},"\
168
+ " got #{config[:limit]}"
167
169
  verify_option_is_correct(:limit, failure_message)
168
170
  end
169
171
 
170
172
  def update_only_correct?
171
- failure_message = "#{should_or_should_not(@options[:update_only])} be update only"
173
+ failure_message = "#{should_or_should_not(@options[:update_only])}"\
174
+ ' be update only'
172
175
  verify_option_is_correct(:update_only, failure_message)
173
176
  end
174
177