shoulda-matchers 3.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
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