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.
- checksums.yaml +5 -5
- data/{MIT-LICENSE → LICENSE} +1 -1
- data/README.md +407 -232
- data/docs/errors/NonCaseSwappableValueError.md +2 -2
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +7 -80
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +4 -3
- data/lib/shoulda/matchers/action_controller/flash_store.rb +2 -4
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +36 -30
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +8 -10
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +7 -9
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +18 -15
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +3 -2
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +3 -3
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +88 -29
- data/lib/shoulda/matchers/action_controller/route_params.rb +2 -2
- data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +4 -4
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -3
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
- data/lib/shoulda/matchers/action_controller.rb +2 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -9
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +42 -39
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +52 -26
- data/lib/shoulda/matchers/active_model/helpers.rb +2 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -30
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +2 -1
- data/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
- data/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
- data/lib/shoulda/matchers/active_model/qualifiers.rb +2 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -6
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +8 -3
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +31 -16
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +52 -16
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +137 -84
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +159 -46
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +130 -66
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +251 -24
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +12 -9
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +38 -6
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
- data/lib/shoulda/matchers/active_model/validator.rb +4 -9
- data/lib/shoulda/matchers/active_model.rb +3 -5
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +10 -7
- data/lib/shoulda/matchers/active_record/association_matcher.rb +386 -111
- data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
- data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +14 -15
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +30 -8
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +34 -11
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +69 -0
- data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +74 -0
- data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
- data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +458 -42
- data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +185 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +63 -23
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +164 -48
- data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +106 -0
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +13 -11
- data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
- data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
- data/lib/shoulda/matchers/active_record/serialize_matcher.rb +18 -18
- data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
- data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
- data/lib/shoulda/matchers/active_record/uniqueness.rb +1 -1
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +430 -200
- data/lib/shoulda/matchers/active_record.rb +28 -20
- data/lib/shoulda/matchers/configuration.rb +12 -1
- data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
- data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
- data/lib/shoulda/matchers/doublespeak/object_double.rb +6 -2
- data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
- data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
- data/lib/shoulda/matchers/doublespeak.rb +2 -1
- data/lib/shoulda/matchers/error.rb +1 -1
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +109 -29
- data/lib/shoulda/matchers/independent.rb +2 -2
- data/lib/shoulda/matchers/integrations/configuration.rb +8 -4
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
- data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
- data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
- data/lib/shoulda/matchers/rails_shim.rb +172 -51
- data/lib/shoulda/matchers/routing.rb +2 -2
- data/lib/shoulda/matchers/util/word_wrap.rb +17 -12
- data/lib/shoulda/matchers/util.rb +39 -5
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers/warn.rb +4 -3
- data/shoulda-matchers.gemspec +33 -15
- metadata +31 -338
- data/.gitignore +0 -12
- data/.hound.yml +0 -3
- data/.hound_config/ruby.yml +0 -12
- data/.travis.yml +0 -19
- data/.yardopts +0 -10
- data/Appraisals +0 -73
- data/CONTRIBUTING.md +0 -101
- data/Gemfile +0 -15
- data/Gemfile.lock +0 -70
- data/NEWS.md +0 -986
- data/Rakefile +0 -39
- data/custom_plan.rb +0 -88
- data/doc_config/gh-pages/index.html.erb +0 -9
- data/doc_config/yard/setup.rb +0 -22
- data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -5967
- data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +0 -12
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +0 -62
- data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +0 -69
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +0 -312
- data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -32
- data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +0 -1
- data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +0 -8
- data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -298
- data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +0 -1
- data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +0 -289
- data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +0 -6
- data/doc_config/yard/templates/default/fulldoc/html/setup.rb +0 -8
- data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +0 -14
- data/doc_config/yard/templates/default/layout/html/fonts.erb +0 -1
- data/doc_config/yard/templates/default/layout/html/footer.erb +0 -6
- data/doc_config/yard/templates/default/layout/html/layout.erb +0 -23
- data/doc_config/yard/templates/default/layout/html/search.erb +0 -13
- data/doc_config/yard/templates/default/layout/html/setup.rb +0 -40
- data/doc_config/yard/templates/default/method_details/html/source.erb +0 -10
- data/doc_config/yard/templates/default/module/html/box_info.erb +0 -31
- data/gemfiles/4.0.0.gemfile +0 -38
- data/gemfiles/4.0.0.gemfile.lock +0 -223
- data/gemfiles/4.0.1.gemfile +0 -38
- data/gemfiles/4.0.1.gemfile.lock +0 -225
- data/gemfiles/4.1.gemfile +0 -38
- data/gemfiles/4.1.gemfile.lock +0 -220
- data/gemfiles/4.2.gemfile +0 -38
- data/gemfiles/4.2.gemfile.lock +0 -243
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +0 -159
- data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +0 -37
- data/script/SUPPORTED_VERSIONS +0 -1
- data/script/install_gems_in_all_appraisals +0 -14
- data/script/run_all_tests +0 -14
- data/script/update_gem_in_all_appraisals +0 -15
- data/script/update_gems_in_all_appraisals +0 -14
- data/spec/acceptance/active_model_integration_spec.rb +0 -23
- data/spec/acceptance/independent_matchers_spec.rb +0 -125
- data/spec/acceptance/multiple_libraries_integration_spec.rb +0 -55
- data/spec/acceptance/rails_integration_spec.rb +0 -156
- data/spec/acceptance_spec_helper.rb +0 -23
- data/spec/doublespeak_spec_helper.rb +0 -2
- data/spec/report_warnings.rb +0 -7
- data/spec/spec_helper.rb +0 -21
- data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +0 -133
- data/spec/support/acceptance/helpers/active_model_helpers.rb +0 -11
- data/spec/support/acceptance/helpers/array_helpers.rb +0 -13
- data/spec/support/acceptance/helpers/base_helpers.rb +0 -19
- data/spec/support/acceptance/helpers/command_helpers.rb +0 -55
- data/spec/support/acceptance/helpers/file_helpers.rb +0 -19
- data/spec/support/acceptance/helpers/gem_helpers.rb +0 -31
- data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -11
- data/spec/support/acceptance/helpers/n_unit_helpers.rb +0 -25
- data/spec/support/acceptance/helpers/pluralization_helpers.rb +0 -13
- data/spec/support/acceptance/helpers/rails_version_helpers.rb +0 -11
- data/spec/support/acceptance/helpers/rspec_helpers.rb +0 -24
- data/spec/support/acceptance/helpers/ruby_version_helpers.rb +0 -9
- data/spec/support/acceptance/helpers/step_helpers.rb +0 -127
- data/spec/support/acceptance/helpers.rb +0 -31
- data/spec/support/acceptance/matchers/have_output.rb +0 -31
- data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +0 -55
- data/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +0 -103
- data/spec/support/tests/bundle.rb +0 -94
- data/spec/support/tests/command_runner.rb +0 -230
- data/spec/support/tests/current_bundle.rb +0 -61
- data/spec/support/tests/database.rb +0 -28
- data/spec/support/tests/database_adapters/postgresql.rb +0 -25
- data/spec/support/tests/database_adapters/sqlite3.rb +0 -26
- data/spec/support/tests/database_configuration.rb +0 -33
- data/spec/support/tests/database_configuration_registry.rb +0 -28
- data/spec/support/tests/filesystem.rb +0 -100
- data/spec/support/tests/version.rb +0 -45
- data/spec/support/unit/active_record/create_table.rb +0 -54
- data/spec/support/unit/attribute.rb +0 -47
- data/spec/support/unit/capture.rb +0 -40
- data/spec/support/unit/change_value.rb +0 -111
- data/spec/support/unit/create_model_arguments/basic.rb +0 -135
- data/spec/support/unit/create_model_arguments/has_many.rb +0 -15
- data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +0 -74
- data/spec/support/unit/helpers/active_model_helpers.rb +0 -27
- data/spec/support/unit/helpers/active_model_versions.rb +0 -28
- data/spec/support/unit/helpers/active_record_versions.rb +0 -24
- data/spec/support/unit/helpers/active_resource_builder.rb +0 -27
- data/spec/support/unit/helpers/allow_value_matcher_helpers.rb +0 -15
- data/spec/support/unit/helpers/class_builder.rb +0 -90
- data/spec/support/unit/helpers/column_type_helpers.rb +0 -26
- data/spec/support/unit/helpers/confirmation_matcher_helpers.rb +0 -17
- data/spec/support/unit/helpers/controller_builder.rb +0 -63
- data/spec/support/unit/helpers/database_helpers.rb +0 -20
- data/spec/support/unit/helpers/i18n_faker.rb +0 -15
- data/spec/support/unit/helpers/mailer_builder.rb +0 -12
- data/spec/support/unit/helpers/model_builder.rb +0 -114
- data/spec/support/unit/helpers/rails_versions.rb +0 -28
- data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +0 -44
- data/spec/support/unit/i18n.rb +0 -7
- data/spec/support/unit/load_environment.rb +0 -12
- data/spec/support/unit/matchers/deprecate.rb +0 -60
- data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +0 -51
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +0 -62
- data/spec/support/unit/matchers/print_warning_including.rb +0 -59
- data/spec/support/unit/model_creation_strategies/active_model.rb +0 -111
- data/spec/support/unit/model_creation_strategies/active_record.rb +0 -77
- data/spec/support/unit/model_creators/active_model.rb +0 -39
- data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +0 -95
- data/spec/support/unit/model_creators/active_record/has_many.rb +0 -67
- data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +0 -42
- data/spec/support/unit/model_creators/active_record.rb +0 -43
- data/spec/support/unit/model_creators/basic.rb +0 -97
- data/spec/support/unit/model_creators.rb +0 -19
- data/spec/support/unit/rails_application.rb +0 -126
- data/spec/support/unit/record_builder_with_i18n_validation_message.rb +0 -69
- data/spec/support/unit/record_validating_confirmation_builder.rb +0 -51
- data/spec/support/unit/record_with_different_error_attribute_builder.rb +0 -92
- data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +0 -79
- data/spec/support/unit/shared_examples/numerical_submatcher.rb +0 -17
- data/spec/support/unit/shared_examples/set_session_or_flash.rb +0 -360
- data/spec/support/unit/validation_matcher_scenario.rb +0 -62
- data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +0 -82
- data/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +0 -28
- data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +0 -592
- data/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +0 -42
- data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +0 -76
- data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +0 -62
- data/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +0 -90
- data/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +0 -31
- data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +0 -330
- data/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb +0 -30
- data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +0 -67
- data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +0 -17
- data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +0 -562
- data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -115
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +0 -823
- data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -86
- data/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +0 -20
- data/spec/unit/shoulda/matchers/active_model/helpers_spec.rb +0 -162
- data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +0 -266
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +0 -91
- data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +0 -149
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -207
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -1015
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -288
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +0 -1837
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -380
- data/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -107
- data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +0 -1242
- data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +0 -251
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +0 -168
- data/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +0 -111
- data/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +0 -85
- data/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +0 -41
- data/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +0 -86
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +0 -1418
- data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +0 -190
- data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +0 -21
- data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +0 -271
- data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +0 -77
- data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +0 -72
- data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +0 -101
- data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +0 -80
- data/spec/unit/shoulda/matchers/doublespeak_spec.rb +0 -27
- data/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb +0 -43
- data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +0 -517
- data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +0 -242
- data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +0 -252
- data/spec/unit_spec_helper.rb +0 -46
- data/spec/warnings_spy/filesystem.rb +0 -45
- data/spec/warnings_spy/partitioner.rb +0 -36
- data/spec/warnings_spy/reader.rb +0 -53
- data/spec/warnings_spy/reporter.rb +0 -88
- data/spec/warnings_spy.rb +0 -64
- data/tasks/documentation.rb +0 -199
- 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
|