shoulda-matchers 3.1.3 → 4.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.hound/ruby.yml +336 -316
- data/.python-version +1 -0
- data/.rubocop.yml +3 -1
- data/.travis.yml +7 -6
- data/Appraisals +76 -44
- data/CONTRIBUTING.md +137 -66
- data/Gemfile +5 -5
- data/Gemfile.lock +30 -35
- data/MAINTAINING.md +250 -0
- data/MIT-LICENSE +1 -1
- data/NEWS.md +176 -4
- data/README.md +138 -200
- data/Rakefile +7 -0
- data/bin/setup +190 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +4 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -6
- data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -17
- data/doc_config/yard/templates/default/fulldoc/html/setup.rb +27 -0
- data/gemfiles/4.2.gemfile +21 -20
- data/gemfiles/4.2.gemfile.lock +143 -140
- data/gemfiles/5.0.gemfile +37 -0
- data/gemfiles/5.0.gemfile.lock +238 -0
- data/gemfiles/5.1.gemfile +38 -0
- data/gemfiles/5.1.gemfile.lock +254 -0
- data/gemfiles/5.2.gemfile +40 -0
- data/gemfiles/5.2.gemfile.lock +273 -0
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +18 -6
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -1
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +87 -27
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +1 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +0 -4
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +5 -0
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -0
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +26 -11
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +39 -4
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +116 -47
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +127 -38
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +55 -37
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +30 -1
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +11 -4
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +11 -6
- data/lib/shoulda/matchers/active_record.rb +3 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +172 -22
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +11 -6
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +46 -0
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +51 -0
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +268 -38
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +111 -0
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +207 -79
- data/lib/shoulda/matchers/doublespeak/object_double.rb +5 -1
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +100 -21
- data/lib/shoulda/matchers/rails_shim.rb +133 -52
- data/lib/shoulda/matchers/routing.rb +2 -2
- data/lib/shoulda/matchers/util.rb +23 -1
- data/lib/shoulda/matchers/util/word_wrap.rb +6 -2
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/install_gems_in_all_appraisals +3 -1
- data/script/run_all_tests +3 -1
- data/script/supported_ruby_versions +7 -0
- data/script/update_gem_in_all_appraisals +3 -1
- data/script/update_gems_in_all_appraisals +3 -1
- data/shoulda-matchers.gemspec +3 -3
- data/spec/acceptance/independent_matchers_spec.rb +2 -2
- data/spec/acceptance/multiple_libraries_integration_spec.rb +1 -1
- data/spec/acceptance/rails_integration_spec.rb +2 -2
- data/spec/spec_helper.rb +2 -3
- data/spec/support/acceptance/helpers.rb +2 -0
- data/spec/support/acceptance/helpers/command_helpers.rb +17 -4
- data/spec/support/acceptance/helpers/rails_migration_helpers.rb +21 -0
- data/spec/support/acceptance/helpers/step_helpers.rb +1 -1
- data/spec/support/tests/current_bundle.rb +3 -9
- data/spec/support/tests/filesystem.rb +2 -2
- data/spec/support/unit/attribute.rb +0 -2
- data/spec/support/unit/capture.rb +9 -3
- data/spec/support/unit/helpers/action_pack_versions.rb +22 -0
- data/spec/support/unit/helpers/active_model_versions.rb +4 -0
- data/spec/support/unit/helpers/active_record_versions.rb +22 -2
- data/spec/support/unit/helpers/active_resource_builder.rb +2 -2
- data/spec/support/unit/helpers/controller_builder.rb +1 -1
- data/spec/support/unit/helpers/message_helpers.rb +19 -0
- data/spec/support/unit/helpers/rails_versions.rb +14 -0
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +7 -5
- data/spec/support/unit/matchers/print_warning_including.rb +21 -13
- data/spec/support/unit/model_creation_strategies/active_record.rb +1 -1
- data/spec/support/unit/model_creators/active_record.rb +0 -1
- data/spec/support/unit/model_creators/basic.rb +7 -2
- data/spec/support/unit/rails_application.rb +25 -0
- data/spec/support/unit/record_validating_confirmation_builder.rb +5 -2
- data/spec/support/unit/validation_matcher_scenario.rb +0 -2
- data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +18 -18
- data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +33 -5
- data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +1 -1
- data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +80 -78
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +7 -9
- data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +28 -4
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +19 -1
- data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +27 -4
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +62 -5
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +52 -18
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +51 -4
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +99 -71
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +41 -15
- data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +445 -15
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +615 -93
- data/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb +169 -0
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +167 -97
- data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +2 -4
- data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +152 -19
- data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +258 -94
- data/spec/unit_spec_helper.rb +9 -1
- data/zeus.json +1 -1
- metadata +31 -16
- 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/script/SUPPORTED_VERSIONS +0 -1
@@ -16,10 +16,11 @@ module Shoulda
|
|
16
16
|
def call
|
17
17
|
if description_clauses_for_qualifiers.any?
|
18
18
|
main_description +
|
19
|
+
clause_for_allow_blank_or_nil +
|
19
20
|
', ' +
|
20
21
|
description_clauses_for_qualifiers.to_sentence
|
21
22
|
else
|
22
|
-
main_description
|
23
|
+
main_description + clause_for_allow_blank_or_nil
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -29,14 +30,18 @@ module Shoulda
|
|
29
30
|
|
30
31
|
private
|
31
32
|
|
32
|
-
def
|
33
|
-
description_clauses = []
|
34
|
-
|
33
|
+
def clause_for_allow_blank_or_nil
|
35
34
|
if matcher.try(:expects_to_allow_blank?)
|
36
|
-
|
35
|
+
' as long as it is not blank'
|
37
36
|
elsif matcher.try(:expects_to_allow_nil?)
|
38
|
-
|
37
|
+
' as long as it is not nil'
|
38
|
+
else
|
39
|
+
''
|
39
40
|
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def description_clauses_for_qualifiers
|
44
|
+
description_clauses = []
|
40
45
|
|
41
46
|
if matcher.try(:expects_strict?)
|
42
47
|
description_clauses << 'raising a validation exception'
|
@@ -6,6 +6,8 @@ require "shoulda/matchers/active_record/association_matchers/join_table_matcher"
|
|
6
6
|
require "shoulda/matchers/active_record/association_matchers/order_matcher"
|
7
7
|
require "shoulda/matchers/active_record/association_matchers/through_matcher"
|
8
8
|
require "shoulda/matchers/active_record/association_matchers/dependent_matcher"
|
9
|
+
require "shoulda/matchers/active_record/association_matchers/required_matcher"
|
10
|
+
require "shoulda/matchers/active_record/association_matchers/optional_matcher"
|
9
11
|
require "shoulda/matchers/active_record/association_matchers/source_matcher"
|
10
12
|
require "shoulda/matchers/active_record/association_matchers/model_reflector"
|
11
13
|
require "shoulda/matchers/active_record/association_matchers/model_reflection"
|
@@ -13,6 +15,7 @@ require "shoulda/matchers/active_record/association_matchers/option_verifier"
|
|
13
15
|
require "shoulda/matchers/active_record/have_db_column_matcher"
|
14
16
|
require "shoulda/matchers/active_record/have_db_index_matcher"
|
15
17
|
require "shoulda/matchers/active_record/have_readonly_attribute_matcher"
|
18
|
+
require "shoulda/matchers/active_record/have_secure_token_matcher"
|
16
19
|
require "shoulda/matchers/active_record/serialize_matcher"
|
17
20
|
require "shoulda/matchers/active_record/accept_nested_attributes_for_matcher"
|
18
21
|
require "shoulda/matchers/active_record/define_enum_for_matcher"
|
@@ -217,7 +217,7 @@ module Shoulda
|
|
217
217
|
# should belong_to(:organization).touch(true)
|
218
218
|
# end
|
219
219
|
#
|
220
|
-
#
|
220
|
+
# ##### autosave
|
221
221
|
#
|
222
222
|
# Use `autosave` to assert that the `:autosave` option was specified.
|
223
223
|
#
|
@@ -253,6 +253,44 @@ module Shoulda
|
|
253
253
|
# should belong_to(:organization).inverse_of(:employees)
|
254
254
|
# end
|
255
255
|
#
|
256
|
+
# ##### required
|
257
|
+
#
|
258
|
+
# Use `required` to assert that the association is not allowed to be nil.
|
259
|
+
# (Enabled by default in Rails 5+.)
|
260
|
+
#
|
261
|
+
# class Person < ActiveRecord::Base
|
262
|
+
# belongs_to :organization, required: true
|
263
|
+
# end
|
264
|
+
#
|
265
|
+
# # RSpec
|
266
|
+
# describe Person
|
267
|
+
# it { should belong_to(:organization).required }
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# # Minitest (Shoulda)
|
271
|
+
# class PersonTest < ActiveSupport::TestCase
|
272
|
+
# should belong_to(:organization).required
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# ##### optional
|
276
|
+
#
|
277
|
+
# Use `optional` to assert that the association is allowed to be nil.
|
278
|
+
# (Rails 5+ only.)
|
279
|
+
#
|
280
|
+
# class Person < ActiveRecord::Base
|
281
|
+
# belongs_to :organization, optional: true
|
282
|
+
# end
|
283
|
+
#
|
284
|
+
# # RSpec
|
285
|
+
# describe Person
|
286
|
+
# it { should belong_to(:organization).optional }
|
287
|
+
# end
|
288
|
+
#
|
289
|
+
# # Minitest (Shoulda)
|
290
|
+
# class PersonTest < ActiveSupport::TestCase
|
291
|
+
# should belong_to(:organization).optional
|
292
|
+
# end
|
293
|
+
#
|
256
294
|
# @return [AssociationMatcher]
|
257
295
|
#
|
258
296
|
def belong_to(name)
|
@@ -468,7 +506,7 @@ module Shoulda
|
|
468
506
|
# should have_many(:ideas).validate(false)
|
469
507
|
# end
|
470
508
|
#
|
471
|
-
#
|
509
|
+
# ##### autosave
|
472
510
|
#
|
473
511
|
# Use `autosave` to assert that the `:autosave` option was specified.
|
474
512
|
#
|
@@ -486,6 +524,25 @@ module Shoulda
|
|
486
524
|
# should have_many(:games).autosave(true)
|
487
525
|
# end
|
488
526
|
#
|
527
|
+
# ##### index_errors
|
528
|
+
#
|
529
|
+
# Use `index_errors` to assert that the `:index_errors` option was
|
530
|
+
# specified.
|
531
|
+
#
|
532
|
+
# class Player < ActiveRecord::Base
|
533
|
+
# has_many :games, index_errors: true
|
534
|
+
# end
|
535
|
+
#
|
536
|
+
# # RSpec
|
537
|
+
# RSpec.describe Player, type: :model do
|
538
|
+
# it { should have_many(:games).index_errors(true) }
|
539
|
+
# end
|
540
|
+
#
|
541
|
+
# # Minitest (Shoulda)
|
542
|
+
# class PlayerTest < ActiveSupport::TestCase
|
543
|
+
# should have_many(:games).index_errors(true)
|
544
|
+
# end
|
545
|
+
#
|
489
546
|
# ##### inverse_of
|
490
547
|
#
|
491
548
|
# Use `inverse_of` to assert that the `:inverse_of` option was specified.
|
@@ -696,7 +753,7 @@ module Shoulda
|
|
696
753
|
# should have_one(:parking_card).validate(false)
|
697
754
|
# end
|
698
755
|
#
|
699
|
-
#
|
756
|
+
# ##### autosave
|
700
757
|
#
|
701
758
|
# Use `autosave` to assert that the `:autosave` option was specified.
|
702
759
|
#
|
@@ -714,6 +771,25 @@ module Shoulda
|
|
714
771
|
# should have_one(:bank).autosave(true)
|
715
772
|
# end
|
716
773
|
#
|
774
|
+
# ##### required
|
775
|
+
#
|
776
|
+
# Use `required` to assert that the association is not allowed to be nil.
|
777
|
+
# (Rails 5+ only.)
|
778
|
+
#
|
779
|
+
# class Person < ActiveRecord::Base
|
780
|
+
# has_one :brain, required: true
|
781
|
+
# end
|
782
|
+
#
|
783
|
+
# # RSpec
|
784
|
+
# describe Person
|
785
|
+
# it { should have_one(:brain).required }
|
786
|
+
# end
|
787
|
+
#
|
788
|
+
# # Minitest (Shoulda)
|
789
|
+
# class PersonTest < ActiveSupport::TestCase
|
790
|
+
# should have_one(:brain).required
|
791
|
+
# end
|
792
|
+
#
|
717
793
|
# @return [AssociationMatcher]
|
718
794
|
#
|
719
795
|
def have_one(name)
|
@@ -854,7 +930,7 @@ module Shoulda
|
|
854
930
|
# validate(false)
|
855
931
|
# end
|
856
932
|
#
|
857
|
-
#
|
933
|
+
# ##### autosave
|
858
934
|
#
|
859
935
|
# Use `autosave` to assert that the `:autosave` option was specified.
|
860
936
|
#
|
@@ -891,42 +967,63 @@ module Shoulda
|
|
891
967
|
@options = {}
|
892
968
|
@submatchers = []
|
893
969
|
@missing = ''
|
970
|
+
|
971
|
+
if macro == :belongs_to && RailsShim.active_record_gte_5?
|
972
|
+
required(belongs_to_required_by_default?)
|
973
|
+
end
|
894
974
|
end
|
895
975
|
|
896
976
|
def through(through)
|
897
|
-
|
898
|
-
|
977
|
+
add_submatcher(
|
978
|
+
AssociationMatchers::ThroughMatcher,
|
979
|
+
through,
|
980
|
+
name,
|
981
|
+
)
|
899
982
|
self
|
900
983
|
end
|
901
984
|
|
902
985
|
def dependent(dependent)
|
903
|
-
|
904
|
-
|
986
|
+
add_submatcher(
|
987
|
+
AssociationMatchers::DependentMatcher,
|
988
|
+
dependent,
|
989
|
+
name,
|
990
|
+
)
|
905
991
|
self
|
906
992
|
end
|
907
993
|
|
908
994
|
def order(order)
|
909
|
-
|
910
|
-
|
995
|
+
add_submatcher(
|
996
|
+
AssociationMatchers::OrderMatcher,
|
997
|
+
order,
|
998
|
+
name,
|
999
|
+
)
|
911
1000
|
self
|
912
1001
|
end
|
913
1002
|
|
914
1003
|
def counter_cache(counter_cache = true)
|
915
|
-
|
916
|
-
|
1004
|
+
add_submatcher(
|
1005
|
+
AssociationMatchers::CounterCacheMatcher,
|
1006
|
+
counter_cache,
|
1007
|
+
name,
|
1008
|
+
)
|
917
1009
|
self
|
918
1010
|
end
|
919
1011
|
|
920
1012
|
def inverse_of(inverse_of)
|
921
|
-
|
922
|
-
AssociationMatchers::InverseOfMatcher
|
923
|
-
|
1013
|
+
add_submatcher(
|
1014
|
+
AssociationMatchers::InverseOfMatcher,
|
1015
|
+
inverse_of,
|
1016
|
+
name,
|
1017
|
+
)
|
924
1018
|
self
|
925
1019
|
end
|
926
1020
|
|
927
1021
|
def source(source)
|
928
|
-
|
929
|
-
|
1022
|
+
add_submatcher(
|
1023
|
+
AssociationMatchers::SourceMatcher,
|
1024
|
+
source,
|
1025
|
+
name,
|
1026
|
+
)
|
930
1027
|
self
|
931
1028
|
end
|
932
1029
|
|
@@ -940,6 +1037,11 @@ module Shoulda
|
|
940
1037
|
self
|
941
1038
|
end
|
942
1039
|
|
1040
|
+
def index_errors(index_errors)
|
1041
|
+
@options[:index_errors] = index_errors
|
1042
|
+
self
|
1043
|
+
end
|
1044
|
+
|
943
1045
|
def class_name(class_name)
|
944
1046
|
@options[:class_name] = class_name
|
945
1047
|
self
|
@@ -955,6 +1057,26 @@ module Shoulda
|
|
955
1057
|
self
|
956
1058
|
end
|
957
1059
|
|
1060
|
+
def required(required = true)
|
1061
|
+
remove_submatcher(AssociationMatchers::OptionalMatcher)
|
1062
|
+
add_submatcher(
|
1063
|
+
AssociationMatchers::RequiredMatcher,
|
1064
|
+
name,
|
1065
|
+
required,
|
1066
|
+
)
|
1067
|
+
self
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
def optional
|
1071
|
+
remove_submatcher(AssociationMatchers::RequiredMatcher)
|
1072
|
+
add_submatcher(
|
1073
|
+
AssociationMatchers::OptionalMatcher,
|
1074
|
+
name,
|
1075
|
+
true,
|
1076
|
+
)
|
1077
|
+
self
|
1078
|
+
end
|
1079
|
+
|
958
1080
|
def validate(validate = true)
|
959
1081
|
@options[:validate] = validate
|
960
1082
|
self
|
@@ -994,6 +1116,7 @@ module Shoulda
|
|
994
1116
|
class_name_correct? &&
|
995
1117
|
join_table_correct? &&
|
996
1118
|
autosave_correct? &&
|
1119
|
+
index_errors_correct? &&
|
997
1120
|
conditions_correct? &&
|
998
1121
|
validate_correct? &&
|
999
1122
|
touch_correct? &&
|
@@ -1016,8 +1139,15 @@ module Shoulda
|
|
1016
1139
|
@reflector ||= AssociationMatchers::ModelReflector.new(subject, name)
|
1017
1140
|
end
|
1018
1141
|
|
1019
|
-
def add_submatcher(
|
1020
|
-
|
1142
|
+
def add_submatcher(matcher_class, *args)
|
1143
|
+
remove_submatcher(matcher_class)
|
1144
|
+
submatchers << matcher_class.new(*args)
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def remove_submatcher(matcher_class)
|
1148
|
+
submatchers.delete_if do |submatcher|
|
1149
|
+
submatcher.is_a?(matcher_class)
|
1150
|
+
end
|
1021
1151
|
end
|
1022
1152
|
|
1023
1153
|
def macro_description
|
@@ -1039,12 +1169,12 @@ module Shoulda
|
|
1039
1169
|
|
1040
1170
|
def missing_options
|
1041
1171
|
missing_options = [missing, missing_options_for_failing_submatchers]
|
1042
|
-
missing_options.flatten.
|
1172
|
+
missing_options.flatten.select(&:present?).join(', ')
|
1043
1173
|
end
|
1044
1174
|
|
1045
1175
|
def failing_submatchers
|
1046
|
-
@failing_submatchers ||= submatchers.
|
1047
|
-
matcher.matches?(subject)
|
1176
|
+
@failing_submatchers ||= submatchers.select do |matcher|
|
1177
|
+
!matcher.matches?(subject)
|
1048
1178
|
end
|
1049
1179
|
end
|
1050
1180
|
|
@@ -1148,6 +1278,22 @@ module Shoulda
|
|
1148
1278
|
end
|
1149
1279
|
end
|
1150
1280
|
|
1281
|
+
def index_errors_correct?
|
1282
|
+
return true unless options.key?(:index_errors)
|
1283
|
+
|
1284
|
+
if option_verifier.correct_for_boolean?(
|
1285
|
+
:index_errors,
|
1286
|
+
options[:index_errors]
|
1287
|
+
)
|
1288
|
+
true
|
1289
|
+
else
|
1290
|
+
@missing =
|
1291
|
+
"#{name} should have index_errors set to " +
|
1292
|
+
"#{options[:index_errors]}"
|
1293
|
+
false
|
1294
|
+
end
|
1295
|
+
end
|
1296
|
+
|
1151
1297
|
def conditions_correct?
|
1152
1298
|
if options.key?(:conditions)
|
1153
1299
|
if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions])
|
@@ -1226,6 +1372,10 @@ module Shoulda
|
|
1226
1372
|
def submatchers_match?
|
1227
1373
|
failing_submatchers.empty?
|
1228
1374
|
end
|
1375
|
+
|
1376
|
+
def belongs_to_required_by_default?
|
1377
|
+
::ActiveRecord::Base.belongs_to_required_by_default
|
1378
|
+
end
|
1229
1379
|
end
|
1230
1380
|
end
|
1231
1381
|
end
|
@@ -34,15 +34,16 @@ module Shoulda
|
|
34
34
|
|
35
35
|
def correct_for?(*args)
|
36
36
|
expected_value, name, type = args.reverse
|
37
|
+
|
37
38
|
if expected_value.nil?
|
38
39
|
true
|
39
40
|
else
|
40
|
-
|
41
|
+
type_cast_expected_value = type_cast(
|
41
42
|
type,
|
42
43
|
expected_value_for(type, name, expected_value)
|
43
44
|
)
|
44
45
|
actual_value = type_cast(type, actual_value_for(name))
|
45
|
-
|
46
|
+
type_cast_expected_value == actual_value
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -65,10 +66,14 @@ module Shoulda
|
|
65
66
|
|
66
67
|
def type_cast(type, value)
|
67
68
|
case type
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
when :string, :relation_clause
|
70
|
+
value.to_s
|
71
|
+
when :boolean
|
72
|
+
!!value
|
73
|
+
when :hash
|
74
|
+
Hash(value).stringify_keys
|
75
|
+
else
|
76
|
+
value
|
72
77
|
end
|
73
78
|
end
|
74
79
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class OptionalMatcher
|
7
|
+
attr_reader :missing_option
|
8
|
+
|
9
|
+
def initialize(attribute_name, optional)
|
10
|
+
@optional = optional
|
11
|
+
@submatcher = ActiveModel::AllowValueMatcher.new(nil).
|
12
|
+
for(attribute_name)
|
13
|
+
@missing_option = ''
|
14
|
+
end
|
15
|
+
|
16
|
+
def description
|
17
|
+
"optional: #{optional}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def matches?(subject)
|
21
|
+
if submatcher_passes?(subject)
|
22
|
+
true
|
23
|
+
else
|
24
|
+
@missing_option =
|
25
|
+
'the association should have been defined ' +
|
26
|
+
"with `optional: #{optional}`, but was not"
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :optional, :submatcher
|
34
|
+
|
35
|
+
def submatcher_passes?(subject)
|
36
|
+
if optional
|
37
|
+
submatcher.matches?(subject)
|
38
|
+
else
|
39
|
+
submatcher.does_not_match?(subject)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|