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,1015 +0,0 @@
1
- require 'unit_spec_helper'
2
-
3
- describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :model do
4
- shared_context 'for a generic attribute' do
5
- def self.testing_values_of_option(option_name, &block)
6
- [nil, true, false].each do |option_value|
7
- context_name = "+ #{option_name}"
8
- option_args = []
9
- matches_or_not = ['matches', 'does not match']
10
- to_or_not_to = [:to, :not_to]
11
-
12
- unless option_value == nil
13
- context_name << "(#{option_value})"
14
- option_args = [option_value]
15
- end
16
-
17
- if option_value == false
18
- matches_or_not.reverse!
19
- to_or_not_to.reverse!
20
- end
21
- end
22
- end
23
-
24
- context 'against an integer attribute' do
25
- it_behaves_like 'it supports in_array',
26
- possible_values: (1..5).to_a,
27
- zero: 0,
28
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_FIXNUM
29
-
30
- it_behaves_like 'it supports in_range',
31
- possible_values: 1..5,
32
- zero: 0
33
-
34
- context 'when attribute validates a range of values via custom validation' do
35
- it 'matches ensuring the correct range and messages' do
36
- expect_to_match_ensuring_range_and_messages(2..5, 2, 5)
37
- expect_to_match_ensuring_range_and_messages(2...5, 2, 4)
38
- end
39
- end
40
-
41
- def build_object(options = {}, &block)
42
- build_object_with_generic_attribute(
43
- options.merge(column_type: :integer, value: 1),
44
- &block
45
- )
46
- end
47
-
48
- def add_outside_value_to(values)
49
- values + [values.last + 1]
50
- end
51
-
52
- def validation_matcher_scenario_args
53
- super.deep_merge(column_type: :integer, default_value: 1)
54
- end
55
- end
56
-
57
- context 'against an attribute with a specific column limit' do
58
- it 'does not raise an exception when attempting to use the matcher' do
59
- possible_values = (1..5).to_a
60
- builder = build_object_allowing(possible_values)
61
- assertion = -> { expect_to_match_on_values(builder, possible_values) }
62
- expect(&assertion).not_to raise_error
63
- end
64
-
65
- def build_object(options = {}, &block)
66
- build_object_with_generic_attribute(
67
- options.merge(
68
- column_type: :integer,
69
- column_options: { limit: 2 },
70
- value: 1
71
- ),
72
- &block
73
- )
74
- end
75
-
76
- def expect_to_match_on_values(builder, values, &block)
77
- expect_to_match_in_array(builder, values, &block)
78
- end
79
- end
80
-
81
- context 'against a float attribute' do
82
- it_behaves_like 'it supports in_array',
83
- possible_values: [1.0, 2.0, 3.0, 4.0, 5.0],
84
- zero: 0.0,
85
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_FIXNUM
86
-
87
- it_behaves_like 'it supports in_range',
88
- possible_values: 1.0..5.0,
89
- zero: 0.0
90
-
91
- def build_object(options = {}, &block)
92
- build_object_with_generic_attribute(
93
- options.merge(column_type: :float, value: 1.0),
94
- &block
95
- )
96
- end
97
-
98
- def add_outside_value_to(values)
99
- values + [values.last + 1]
100
- end
101
-
102
- def validation_matcher_scenario_args
103
- super.deep_merge(column_type: :float, default_value: 1.0)
104
- end
105
- end
106
-
107
- context 'against a decimal attribute' do
108
- it_behaves_like 'it supports in_array',
109
- possible_values: [1.0, 2.0, 3.0, 4.0, 5.0].map { |number|
110
- BigDecimal.new(number.to_s)
111
- },
112
- zero: BigDecimal.new('0.0'),
113
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DECIMAL
114
-
115
- it_behaves_like 'it supports in_range',
116
- possible_values: BigDecimal.new('1.0') .. BigDecimal.new('5.0'),
117
- zero: BigDecimal.new('0.0')
118
-
119
- def build_object(options = {}, &block)
120
- build_object_with_generic_attribute(
121
- options.merge(column_type: :decimal, value: BigDecimal.new('1.0')),
122
- &block
123
- )
124
- end
125
-
126
- def add_outside_value_to(values)
127
- values + [values.last + 1]
128
- end
129
-
130
- def validation_matcher_scenario_args
131
- super.deep_merge(
132
- column_type: :decimal,
133
- default_value: BigDecimal.new('1.0')
134
- )
135
- end
136
- end
137
-
138
- context 'against a date attribute' do
139
- today = Date.today
140
-
141
- define_method(:today) { today }
142
-
143
- it_behaves_like 'it supports in_array',
144
- possible_values: (1..5).map { |n| today + n },
145
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DATE
146
-
147
- it_behaves_like 'it supports in_range',
148
- possible_values: (today .. today + 5)
149
-
150
- define_method :build_object do |options = {}, &block|
151
- build_object_with_generic_attribute(
152
- options.merge(column_type: :date, value: today),
153
- &block
154
- )
155
- end
156
-
157
- def add_outside_value_to(values)
158
- values + [values.last + 1]
159
- end
160
-
161
- def validation_matcher_scenario_args
162
- super.deep_merge(column_type: :date, default_value: today)
163
- end
164
- end
165
-
166
- context 'against a datetime attribute' do
167
- now = DateTime.now
168
-
169
- define_method(:now) { now }
170
-
171
- it_behaves_like 'it supports in_array',
172
- possible_values: (1..5).map { |n| now + n },
173
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DATETIME
174
-
175
- it_behaves_like 'it supports in_range',
176
- possible_values: (now .. now + 5)
177
-
178
- define_method :build_object do |options = {}, &block|
179
- build_object_with_generic_attribute(
180
- options.merge(column_type: :datetime, value: now),
181
- &block
182
- )
183
- end
184
-
185
- def add_outside_value_to(values)
186
- values + [values.last + 1]
187
- end
188
-
189
- def validation_matcher_scenario_args
190
- super.deep_merge(column_type: :datetime, default_value: now)
191
- end
192
- end
193
-
194
- context 'against a time attribute' do
195
- now = Time.now
196
-
197
- define_method(:now) { now }
198
-
199
- it_behaves_like 'it supports in_array',
200
- possible_values: (1..5).map { |n| now + n },
201
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_TIME
202
-
203
- it_behaves_like 'it supports in_range',
204
- possible_values: (now .. now + 5)
205
-
206
- define_method :build_object do |options = {}, &block|
207
- build_object_with_generic_attribute(
208
- options.merge(column_type: :time, value: now),
209
- &block
210
- )
211
- end
212
-
213
- def add_outside_value_to(values)
214
- values + [values.last + 1]
215
- end
216
-
217
- def validation_matcher_scenario_args
218
- super.deep_merge(column_type: :time, default_value: now)
219
- end
220
- end
221
-
222
- context 'against a string attribute' do
223
- it_behaves_like 'it supports in_array',
224
- possible_values: %w(foo bar baz),
225
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_STRING
226
-
227
- def build_object(options = {}, &block)
228
- build_object_with_generic_attribute(
229
- options.merge(column_type: :string),
230
- &block
231
- )
232
- end
233
-
234
- def add_outside_value_to(values)
235
- values + %w(qux)
236
- end
237
-
238
- def validation_matcher_scenario_args
239
- super.deep_merge(column_type: :string)
240
- end
241
- end
242
- end
243
-
244
- shared_examples_for 'it supports allow_nil' do |args|
245
- valid_values = args.fetch(:valid_values)
246
-
247
- testing_values_of_option 'allow_nil' do |option_args, matches_or_not, to_or_not_to|
248
- it "#{matches_or_not[0]} when the validation specifies allow_nil" do
249
- builder = build_object_allowing(
250
- valid_values,
251
- validation_options: { allow_nil: true }
252
- )
253
-
254
- __send__("expect_#{to_or_not_to[0]}_match_on_values", builder, valid_values) do |matcher|
255
- matcher.allow_nil(*option_args)
256
- end
257
- end
258
-
259
- it "#{matches_or_not[1]} when the validation does not specify allow_nil" do
260
- builder = build_object_allowing(valid_values)
261
-
262
- __send__("expect_#{to_or_not_to[1]}_match_on_values", builder, valid_values) do |matcher|
263
- matcher.allow_nil(*option_args)
264
- end
265
- end
266
- end
267
-
268
- =begin
269
- it_supports(
270
- 'ignoring_interference_by_writer',
271
- tests: {
272
- accept_if_qualified_but_changing_value_does_not_interfere: {
273
- changing_values_with: -> (value) { value || valid_values.first }
274
- },
275
- reject_if_qualified_but_changing_value_interferes: {
276
- attribute_name: :attr,
277
- changing_values_with: :never_falsy,
278
- expected_message_includes: <<-MESSAGE.strip
279
- As indicated in the message above, :attr seems to be changing certain
280
- values as they are set, and this could have something to do with why
281
- this test is failing. If you've overridden the writer method for this
282
- attribute, then you may need to change it to make this test pass, or
283
- do something else entirely.
284
- MESSAGE
285
- }
286
- }
287
- )
288
- =end
289
-
290
- def validation_matcher_scenario_args
291
- super.deep_merge(validation_options: { allow_nil: true })
292
- end
293
-
294
- def configure_validation_matcher(matcher)
295
- super(matcher).allow_nil
296
- end
297
- end
298
-
299
- shared_examples_for 'it supports allow_blank' do |args|
300
- valid_values = args.fetch(:valid_values)
301
-
302
- testing_values_of_option 'allow_blank' do |option_args, matches_or_not, to_or_not_to|
303
- it "#{matches_or_not[0]} when the validation specifies allow_blank" do
304
- builder = build_object_allowing(
305
- valid_values,
306
- validation_options: { allow_blank: true }
307
- )
308
-
309
- __send__("expect_#{to_or_not_to[0]}_match_on_values", builder, valid_values) do |matcher|
310
- matcher.allow_blank(*option_args)
311
- end
312
- end
313
-
314
- it "#{matches_or_not[1]} when the validation does not specify allow_blank" do
315
- builder = build_object_allowing(valid_values)
316
-
317
- __send__("expect_#{to_or_not_to[1]}_match_on_values", builder, valid_values) do |matcher|
318
- matcher.allow_blank(*option_args)
319
- end
320
- end
321
- end
322
-
323
- =begin
324
- it_supports(
325
- 'ignoring_interference_by_writer',
326
- tests: {
327
- accept_if_qualified_but_changing_value_does_not_interfere: {
328
- changing_values_with: -> (value) {
329
- value.presence || valid_values.first
330
- }
331
- },
332
- reject_if_qualified_but_changing_value_interferes: {
333
- attribute_name: :attr,
334
- changing_values_with: :never_blank,
335
- expected_message_includes: <<-MESSAGE.strip
336
- As indicated in the message above, :attr seems to be changing certain
337
- values as they are set, and this could have something to do with why
338
- this test is failing. If you've overridden the writer method for this
339
- attribute, then you may need to change it to make this test pass, or
340
- do something else entirely.
341
- MESSAGE
342
- }
343
- }
344
- )
345
- =end
346
-
347
- def validation_matcher_scenario_args
348
- super.deep_merge(validation_options: { allow_blank: true })
349
- end
350
-
351
- def configure_validation_matcher(matcher)
352
- super(matcher).allow_blank
353
- end
354
- end
355
-
356
- shared_examples_for 'it supports with_message' do |args|
357
- valid_values = args.fetch(:valid_values)
358
-
359
- context 'given a string' do
360
- it 'matches when validation uses given message' do
361
- builder = build_object_allowing(
362
- valid_values,
363
- validation_options: { message: 'a message' }
364
- )
365
-
366
- expect_to_match_on_values(builder, valid_values) do |matcher|
367
- matcher.with_message('a message')
368
- end
369
- end
370
-
371
- it 'does not match when validation uses the default message instead of given message' do
372
- builder = build_object_allowing(valid_values)
373
-
374
- expect_not_to_match_on_values(builder, valid_values) do |matcher|
375
- matcher.with_message('a message')
376
- end
377
- end
378
-
379
- it 'does not match when validation uses a message but it is not same as given' do
380
- builder = build_object_allowing(
381
- valid_values,
382
- validation_options: { message: 'a different message' }
383
- )
384
-
385
- expect_not_to_match_on_values(builder, valid_values) do |matcher|
386
- matcher.with_message('a message')
387
- end
388
- end
389
- end
390
-
391
- context 'given a regex' do
392
- it 'matches when validation uses a message that matches the regex' do
393
- builder = build_object_allowing(
394
- valid_values,
395
- validation_options: { message: 'this is a message' }
396
- )
397
-
398
- expect_to_match_on_values(builder, valid_values) do |matcher|
399
- matcher.with_message(/a message/)
400
- end
401
- end
402
-
403
- it 'does not match when validation uses the default message instead of given message' do
404
- builder = build_object_allowing(valid_values)
405
-
406
- expect_not_to_match_on_values(builder, valid_values) do |matcher|
407
- matcher.with_message(/a message/)
408
- end
409
- end
410
-
411
- it 'does not match when validation uses a message but it does not match regex' do
412
- builder = build_object_allowing(
413
- valid_values,
414
- validation_options: { message: 'a different message' }
415
- )
416
-
417
- expect_not_to_match_on_values(builder, valid_values) do |matcher|
418
- matcher.with_message(/a message/)
419
- end
420
- end
421
- end
422
-
423
- context 'given nil' do
424
- it 'is as if with_message had never been called' do
425
- builder = build_object_allowing(valid_values)
426
-
427
- expect_to_match_on_values(builder, valid_values) do |matcher|
428
- matcher.with_message(nil)
429
- end
430
- end
431
- end
432
- end
433
-
434
- shared_examples_for 'it supports in_array' do |args|
435
- possible_values = args.fetch(:possible_values)
436
- zero = args[:zero]
437
- reserved_outside_value = args.fetch(:reserved_outside_value)
438
-
439
- define_method(:valid_values) { args.fetch(:possible_values) }
440
-
441
- it 'does not match a record with no validations' do
442
- builder = build_object
443
- expect_not_to_match_on_values(builder, possible_values)
444
- end
445
-
446
- it 'matches given the same array of valid values' do
447
- builder = build_object_allowing(possible_values)
448
- expect_to_match_on_values(builder, possible_values)
449
- end
450
-
451
- it 'matches given a subset of the valid values' do
452
- builder = build_object_allowing(possible_values)
453
- expect_to_match_on_values(builder, possible_values[1..-1])
454
- end
455
-
456
- if zero
457
- it 'matches when one of the given values is a zero' do
458
- valid_values = possible_values + [zero]
459
- builder = build_object_allowing(valid_values)
460
- expect_to_match_on_values(builder, valid_values)
461
- end
462
- end
463
-
464
- it 'does not match when one of the given values is invalid' do
465
- builder = build_object_allowing(possible_values)
466
- expect_not_to_match_on_values(builder, add_outside_value_to(possible_values))
467
- end
468
-
469
- it 'raises an error when valid and given value is our test outside value' do
470
- error_class = Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray
471
- builder = build_object_allowing([reserved_outside_value])
472
-
473
- expect { expect_to_match_on_values(builder, [reserved_outside_value]) }.
474
- to raise_error(error_class)
475
- end
476
-
477
- it_behaves_like 'it supports allow_nil', valid_values: possible_values
478
- it_behaves_like 'it supports allow_blank', valid_values: possible_values
479
- it_behaves_like 'it supports with_message', valid_values: possible_values
480
-
481
- if active_model_3_2?
482
- context '+ strict' do
483
- context 'when the validation specifies strict' do
484
- it 'matches when the given values match the valid values' do
485
- builder = build_object_allowing(
486
- possible_values,
487
- validation_options: { strict: true }
488
- )
489
-
490
- expect_to_match_on_values(builder, possible_values) do |matcher|
491
- matcher.strict
492
- end
493
- end
494
-
495
- it 'does not match when the given values do not match the valid values' do
496
- builder = build_object_allowing(
497
- possible_values,
498
- validation_options: { strict: true }
499
- )
500
-
501
- values = add_outside_value_to(possible_values)
502
- expect_not_to_match_on_values(builder, values) do |matcher|
503
- matcher.strict
504
- end
505
- end
506
- end
507
-
508
- context 'when the validation does not specify strict' do
509
- it 'does not match' do
510
- builder = build_object_allowing(possible_values)
511
-
512
- expect_not_to_match_on_values(builder, possible_values) do |matcher|
513
- matcher.strict
514
- end
515
- end
516
- end
517
- end
518
- end
519
-
520
- it_supports(
521
- 'ignoring_interference_by_writer',
522
- tests: {
523
- reject_if_qualified_but_changing_value_interferes: {
524
- attribute_name: :attr,
525
- changing_values_with: :next_value,
526
- expected_message_includes: <<-MESSAGE.strip
527
- As indicated in the message above, :attr seems to be changing certain
528
- values as they are set, and this could have something to do with why
529
- this test is failing. If you've overridden the writer method for this
530
- attribute, then you may need to change it to make this test pass, or
531
- do something else entirely.
532
- MESSAGE
533
- }
534
- }
535
- )
536
-
537
- def expect_to_match_on_values(builder, values, &block)
538
- expect_to_match_in_array(builder, values, &block)
539
- end
540
-
541
- def expect_not_to_match_on_values(builder, values, &block)
542
- expect_not_to_match_in_array(builder, values, &block)
543
- end
544
-
545
- def validation_matcher_scenario_args
546
- super.deep_merge(validation_options: { in: valid_values })
547
- end
548
-
549
- def configure_validation_matcher(matcher)
550
- super(matcher).in_array(valid_values)
551
- end
552
- end
553
-
554
- shared_examples_for 'it supports in_range' do |args|
555
- possible_values = args[:possible_values]
556
-
557
- define_method(:valid_values) { args.fetch(:possible_values) }
558
-
559
- it 'does not match a record with no validations' do
560
- builder = build_object
561
- expect_not_to_match_on_values(builder, possible_values)
562
- end
563
-
564
- it 'matches given a range that exactly matches the valid range' do
565
- builder = build_object_allowing(possible_values)
566
- expect_to_match_on_values(builder, possible_values)
567
- end
568
-
569
- it 'does not match given a range whose start value falls outside valid range' do
570
- builder = build_object_allowing(possible_values)
571
- expect_not_to_match_on_values(builder,
572
- Range.new(possible_values.first - 1, possible_values.last)
573
- )
574
- end
575
-
576
- it 'does not match given a range whose start value falls inside valid range' do
577
- builder = build_object_allowing(possible_values)
578
- expect_not_to_match_on_values(builder,
579
- Range.new(possible_values.first + 1, possible_values.last)
580
- )
581
- end
582
-
583
- it 'does not match given a range whose end value falls inside valid range' do
584
- builder = build_object_allowing(possible_values)
585
- expect_not_to_match_on_values(builder,
586
- Range.new(possible_values.first, possible_values.last - 1)
587
- )
588
- end
589
-
590
- it 'does not match given a range whose end value falls outside valid range' do
591
- builder = build_object_allowing(possible_values)
592
- expect_not_to_match_on_values(builder,
593
- Range.new(possible_values.first, possible_values.last + 1)
594
- )
595
- end
596
-
597
- it_behaves_like 'it supports allow_nil', valid_values: possible_values
598
- it_behaves_like 'it supports allow_blank', valid_values: possible_values
599
- it_behaves_like 'it supports with_message', valid_values: possible_values
600
-
601
- if active_model_3_2?
602
- context '+ strict' do
603
- context 'when the validation specifies strict' do
604
- it 'matches when the given range matches the range in the validation' do
605
- builder = build_object_allowing(
606
- possible_values,
607
- validation_options: { strict: true }
608
- )
609
-
610
- expect_to_match_on_values(builder, possible_values) do |matcher|
611
- matcher.strict
612
- end
613
- end
614
-
615
- it 'matches when the given range does not match the range in the validation' do
616
- builder = build_object_allowing(
617
- possible_values,
618
- validation_options: { strict: true }
619
- )
620
-
621
- range = Range.new(possible_values.first, possible_values.last + 1)
622
- expect_not_to_match_on_values(builder, range) do |matcher|
623
- matcher.strict
624
- end
625
- end
626
- end
627
-
628
- context 'when the validation does not specify strict' do
629
- it 'does not match' do
630
- builder = build_object_allowing(possible_values)
631
-
632
- expect_not_to_match_on_values(builder, possible_values) do |matcher|
633
- matcher.strict
634
- end
635
- end
636
- end
637
- end
638
- end
639
-
640
- it_supports(
641
- 'ignoring_interference_by_writer',
642
- tests: {
643
- reject_if_qualified_but_changing_value_interferes: {
644
- attribute_name: :attr,
645
- changing_values_with: :next_value,
646
- expected_message_includes: <<-MESSAGE.strip
647
- As indicated in the message above, :attr seems to be changing certain
648
- values as they are set, and this could have something to do with why
649
- this test is failing. If you've overridden the writer method for this
650
- attribute, then you may need to change it to make this test pass, or
651
- do something else entirely.
652
- MESSAGE
653
- }
654
- }
655
- )
656
-
657
- def expect_to_match_on_values(builder, range, &block)
658
- expect_to_match_in_range(builder, range, &block)
659
- end
660
-
661
- def expect_not_to_match_on_values(builder, range, &block)
662
- expect_not_to_match_in_range(builder, range, &block)
663
- end
664
-
665
- def validation_matcher_scenario_args
666
- super.deep_merge(validation_options: { in: valid_values })
667
- end
668
-
669
- def configure_validation_matcher(matcher)
670
- super(matcher).in_range(valid_values)
671
- end
672
- end
673
-
674
- shared_context 'against a boolean attribute for true and false' do
675
- context 'when ensuring inclusion of true' do
676
- it 'matches' do
677
- valid_values = [true]
678
- builder = build_object_allowing(valid_values)
679
- expect_to_match_in_array(builder, valid_values)
680
- end
681
- end
682
-
683
- context 'when ensuring inclusion of false' do
684
- it 'matches' do
685
- valid_values = [false]
686
- builder = build_object_allowing(valid_values)
687
- expect_to_match_in_array(builder, valid_values)
688
- end
689
- end
690
-
691
- context 'when ensuring inclusion of true and false' do
692
- it 'matches' do
693
- valid_values = [true, false]
694
- builder = build_object_allowing(valid_values)
695
- silence_stderr do
696
- expect_to_match_in_array(builder, valid_values)
697
- end
698
- end
699
-
700
- [[false, true], [true, false]].each do |booleans|
701
- it 'prints a warning' do
702
- valid_values = booleans
703
- builder = build_object_allowing(valid_values)
704
- message = 'You are using `validate_inclusion_of` to assert that a boolean column allows boolean values and disallows non-boolean ones'
705
-
706
- stderr = capture(:stderr) do
707
- expect_to_match_in_array(builder, valid_values)
708
- end
709
-
710
- expect(stderr.gsub(/\n+/, ' ')).to include(message)
711
- end
712
- end
713
- end
714
- end
715
-
716
- context 'for a database column' do
717
- include_context 'for a generic attribute'
718
-
719
- context 'against a timestamp column' do
720
- now = DateTime.now
721
-
722
- define_method(:now) { now }
723
-
724
- it_behaves_like 'it supports in_array',
725
- possible_values: (1..5).map { |n| now + n },
726
- reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DATETIME
727
-
728
- it_behaves_like 'it supports in_range',
729
- possible_values: (now .. now + 5)
730
-
731
- define_method :build_object do |options = {}, &block|
732
- build_object_with_generic_attribute(
733
- options.merge(column_type: :timestamp, value: now),
734
- &block
735
- )
736
- end
737
-
738
- def add_outside_value_to(values)
739
- values + [values.last + 1]
740
- end
741
-
742
- def validation_matcher_scenario_args
743
- super.deep_merge(column_type: :timestamp, default_value: now)
744
- end
745
- end
746
-
747
- context 'against a boolean attribute' do
748
- context 'which is nullable' do
749
- include_context 'against a boolean attribute for true and false'
750
-
751
- context 'when ensuring inclusion of nil' do
752
- it 'matches' do
753
- valid_values = [nil]
754
- builder = build_object_allowing(valid_values)
755
- silence_stderr do
756
- expect_to_match_in_array(builder, valid_values)
757
- end
758
- end
759
-
760
- it 'prints a warning' do
761
- valid_values = [nil]
762
- builder = build_object_allowing(valid_values)
763
- message = 'You are using `validate_inclusion_of` to assert that a boolean column allows nil'
764
-
765
- stderr = capture(:stderr) do
766
- expect_to_match_in_array(builder, valid_values)
767
- end
768
-
769
- expect(stderr.gsub(/\n+/, ' ')).to include(message)
770
- end
771
- end
772
-
773
- def build_object(options = {}, &block)
774
- super(options.merge(column_options: { null: true }, value: true))
775
- end
776
- end
777
-
778
- context 'which is non-nullable' do
779
- include_context 'against a boolean attribute for true and false'
780
-
781
- context 'when ensuring inclusion of nil' do
782
- it 'raises a specific error' do
783
- valid_values = [nil]
784
- builder = build_object_allowing(valid_values)
785
- error_class = Shoulda::Matchers::ActiveModel::NonNullableBooleanError
786
-
787
- expect {
788
- expect_to_match_in_array(builder, valid_values)
789
- }.to raise_error(error_class)
790
- end
791
- end
792
-
793
- def build_object(options = {}, &block)
794
- super(options.merge(column_options: { null: false }))
795
- end
796
- end
797
-
798
- def build_object(options = {}, &block)
799
- build_object_with_generic_attribute(
800
- options.merge(column_type: :boolean),
801
- &block
802
- )
803
- end
804
- end
805
-
806
- def define_simple_model(attribute_name: :attr, column_options: {}, &block)
807
- define_model('Example', attribute_name => column_options, &block)
808
- end
809
-
810
- def validation_matcher_scenario_args
811
- super.deep_merge(model_creator: :active_record)
812
- end
813
- end
814
-
815
- context 'for a plain Ruby attribute' do
816
- include_context 'for a generic attribute'
817
-
818
- context 'against a boolean attribute (designated by true)' do
819
- include_context 'against a boolean attribute for true and false'
820
-
821
- def build_object(options = {}, &block)
822
- build_object_with_generic_attribute(options.merge(value: true))
823
- end
824
- end
825
-
826
- context 'against a boolean attribute (designated by false)' do
827
- include_context 'against a boolean attribute for true and false'
828
-
829
- def build_object(options = {}, &block)
830
- build_object_with_generic_attribute(options.merge(value: false))
831
- end
832
- end
833
-
834
- def define_simple_model(attribute_name: :attr, column_options: {}, &block)
835
- define_active_model_class('Example', accessors: [attribute_name], &block)
836
- end
837
-
838
- def validation_matcher_scenario_args
839
- super.deep_merge(model_creator: :active_model)
840
- end
841
- end
842
-
843
- describe '#description' do
844
- context 'given an array of values' do
845
- context 'when there is one value' do
846
- it 'returns the correct string' do
847
- matcher = validate_inclusion_of(:attr).in_array([true])
848
-
849
- expect(matcher.description).to eq(
850
- 'validate that :attr is ‹true›'
851
- )
852
- end
853
- end
854
-
855
- context 'when there are two values' do
856
- it 'returns the correct string' do
857
- matcher = validate_inclusion_of(:attr).in_array([true, 'dog'])
858
-
859
- expect(matcher.description).to eq(
860
- 'validate that :attr is either ‹true› or ‹"dog"›'
861
- )
862
- end
863
- end
864
-
865
- context 'when there are three or more values' do
866
- it 'returns the correct string' do
867
- matcher = validate_inclusion_of(:attr).in_array([true, 'dog', 'cat'])
868
-
869
- expect(matcher.description).to eq(
870
- 'validate that :attr is either ‹true›, ‹"dog"›, or ‹"cat"›'
871
- )
872
- end
873
- end
874
- end
875
-
876
- context 'given a range of values' do
877
- it 'returns the correct string' do
878
- matcher = validate_inclusion_of(:attr).in_range(1..10)
879
-
880
- expect(matcher.description).to eq(
881
- 'validate that :attr lies inside the range ‹1› to ‹10›'
882
- )
883
- end
884
- end
885
- end
886
-
887
- def object_builder_class
888
- @_object_builder_class ||= Struct.new(:attribute, :object, :validation_options)
889
- end
890
-
891
- def build_object_with_generic_attribute(
892
- attribute_name: :attr,
893
- validation_options: nil,
894
- value: nil,
895
- **other_options
896
- )
897
- model = define_model_validating_inclusion(
898
- attribute_name: attribute_name,
899
- validation_options: validation_options,
900
- **other_options
901
- )
902
-
903
- object = model.new
904
- object.__send__("#{attribute_name}=", value)
905
-
906
- object_builder_class.new(attribute_name, object, validation_options)
907
- end
908
-
909
- def define_model_validating_inclusion(
910
- attribute_name: :attr,
911
- column_type: :string,
912
- column_options: {},
913
- validation_options: nil,
914
- custom_validation: nil,
915
- customize_model_class: -> (object) { }
916
- )
917
- column_options = { type: column_type, options: column_options }
918
-
919
- define_simple_model(
920
- attribute_name: attribute_name,
921
- column_options: column_options
922
- ) do |model|
923
- if validation_options
924
- model.validates_inclusion_of(attribute_name, validation_options)
925
- end
926
-
927
- if custom_validation
928
- model.class_eval do
929
- define_method :custom_validation do
930
- custom_validation.call(self, attribute_name)
931
- end
932
-
933
- validate :custom_validation
934
- end
935
- end
936
-
937
- if customize_model_class
938
- model.instance_eval(&customize_model_class)
939
- end
940
- end
941
- end
942
-
943
- def build_object_allowing(values, validation_options: {}, **other_options)
944
- build_object(
945
- validation_options: validation_options.merge(in: values),
946
- **other_options
947
- )
948
- end
949
-
950
- def expect_to_match(builder)
951
- matcher = validate_inclusion_of(builder.attribute)
952
- yield matcher if block_given?
953
- expect(builder.object).to(matcher)
954
- end
955
-
956
- def expect_not_to_match(builder)
957
- matcher = validate_inclusion_of(builder.attribute)
958
- yield matcher if block_given?
959
- expect(builder.object).not_to(matcher)
960
- end
961
-
962
- def expect_to_match_in_array(builder, array)
963
- expect_to_match(builder) do |matcher|
964
- matcher.in_array(array)
965
- yield matcher if block_given?
966
- end
967
- end
968
-
969
- def expect_not_to_match_in_array(builder, array)
970
- expect_not_to_match(builder) do |matcher|
971
- matcher.in_array(array)
972
- yield matcher if block_given?
973
- end
974
- end
975
-
976
- def expect_to_match_in_range(builder, range)
977
- expect_to_match(builder) do |matcher|
978
- matcher.in_range(range)
979
- yield matcher if block_given?
980
- end
981
- end
982
-
983
- def expect_not_to_match_in_range(builder, range)
984
- expect_not_to_match(builder) do |matcher|
985
- matcher.in_range(range)
986
- yield matcher if block_given?
987
- end
988
- end
989
-
990
- def expect_to_match_ensuring_range_and_messages(range, low_value, high_value)
991
- low_message = 'too low'
992
- high_message = 'too high'
993
-
994
- builder = build_object custom_validation: -> (object, attribute) {
995
- value = object.public_send(attribute)
996
-
997
- if value < low_value
998
- object.errors.add(attribute, low_message)
999
- elsif value > high_value
1000
- object.errors.add(attribute, high_message)
1001
- end
1002
- }
1003
-
1004
- expect_to_match(builder) do |matcher|
1005
- matcher.
1006
- in_range(range).
1007
- with_low_message(low_message).
1008
- with_high_message(high_message)
1009
- end
1010
- end
1011
-
1012
- def validation_matcher_scenario_args
1013
- super.deep_merge(matcher_name: :validate_inclusion_of)
1014
- end
1015
- end