shoulda_matchmakers 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +21 -0
  4. data/lib/controller/action_controller/action_controller_controller_sm_model.rb +53 -0
  5. data/lib/controller/action_controller/action_controller_controller_sm_model_helper.rb +73 -0
  6. data/lib/controller/action_controller/matchmakers/callbacks.rb +56 -0
  7. data/lib/controller/action_controller/matchmakers/filter_param.rb +69 -0
  8. data/lib/controller/action_controller/matchmakers/permit.rb +510 -0
  9. data/lib/controller/action_controller/matchmakers/redirect_to.rb +126 -0
  10. data/lib/controller/action_controller/matchmakers/render_template.rb +198 -0
  11. data/lib/controller/action_controller/matchmakers/render_with_layout.rb +72 -0
  12. data/lib/controller/action_controller/matchmakers/rescue_from.rb +96 -0
  13. data/lib/controller/action_controller/matchmakers/respond_with.rb +71 -0
  14. data/lib/controller/action_controller/matchmakers/route.rb +586 -0
  15. data/lib/controller/action_controller/matchmakers/set_flash.rb +136 -0
  16. data/lib/controller/action_controller/matchmakers/set_session.rb +115 -0
  17. data/lib/controller/action_controller/permitted_params_definition.rb +60 -0
  18. data/lib/generators/shoulda_matchmakers/controller_matcher_generator.rb +87 -0
  19. data/lib/generators/shoulda_matchmakers/controller_matcher_generator_helper.rb +92 -0
  20. data/lib/generators/shoulda_matchmakers/factory_generator.rb +86 -0
  21. data/lib/generators/shoulda_matchmakers/install_generator.rb +10 -0
  22. data/lib/generators/shoulda_matchmakers/model_matcher_generator.rb +87 -0
  23. data/lib/generators/shoulda_matchmakers/model_matcher_generator_helper.rb +107 -0
  24. data/lib/model/active_record/active_record_model_sm_model.rb +50 -0
  25. data/lib/model/active_record/active_record_model_sm_model_helper.rb +206 -0
  26. data/lib/model/active_record/factory_sm_model.rb +28 -0
  27. data/lib/model/active_record/factory_sm_model_helper.rb +124 -0
  28. data/lib/model/active_record/matchmakers/accept_nested_attributes_for.rb +66 -0
  29. data/lib/model/active_record/matchmakers/allow_value.rb +137 -0
  30. data/lib/model/active_record/matchmakers/associations.rb +52 -0
  31. data/lib/model/active_record/matchmakers/define_enum_for.rb +53 -0
  32. data/lib/model/active_record/matchmakers/delegate_method.rb +101 -0
  33. data/lib/model/active_record/matchmakers/have_db_column.rb +33 -0
  34. data/lib/model/active_record/matchmakers/have_db_index.rb +39 -0
  35. data/lib/model/active_record/matchmakers/have_readonly_attribute.rb +32 -0
  36. data/lib/model/active_record/matchmakers/have_secure_password.rb +32 -0
  37. data/lib/model/active_record/matchmakers/serialize.rb +67 -0
  38. data/lib/model/active_record/matchmakers/validations.rb +169 -0
  39. data/lib/model/active_record/options_definition.rb +160 -0
  40. data/lib/shoulda_matchmakers.rb +48 -0
  41. data/lib/shoulda_matchmakers/version.rb +3 -0
  42. data/lib/support/command_line_interface.rb +100 -0
  43. data/lib/support/controller_generator.rb +198 -0
  44. data/lib/support/indefinite_article.rb +70 -0
  45. data/lib/support/to_discard/belong_to.rb +94 -0
  46. data/lib/support/to_discard/have_and_belong_to_many.rb +83 -0
  47. data/lib/support/to_discard/have_many.rb +96 -0
  48. data/lib/support/to_discard/have_one.rb +98 -0
  49. data/lib/support/to_discard/permit_refactor.rb +270 -0
  50. data/lib/support/to_discard/render_template_new.rb +204 -0
  51. data/lib/support/to_discard/render_template_reconstruction.rb +188 -0
  52. data/lib/support/to_discard/use_around_action.rb +20 -0
  53. data/lib/support/to_discard/use_before_action.rb +20 -0
  54. data/lib/support/to_discard/validate_absence_of.rb +16 -0
  55. data/lib/support/to_discard/validate_acceptance_of.rb +16 -0
  56. data/lib/support/to_discard/validate_confirmation_of.rb +16 -0
  57. data/lib/support/to_discard/validate_exclusion_of.rb +145 -0
  58. data/lib/support/to_discard/validate_inclusion_of.rb +94 -0
  59. data/lib/support/to_discard/validate_length_of.rb +16 -0
  60. data/lib/support/to_discard/validate_numericality_of.rb +16 -0
  61. data/lib/support/to_discard/validate_presence_of.rb +16 -0
  62. data/lib/support/to_discard/validate_uniqueness_of.rb +16 -0
  63. data/lib/support/to_discard/validation_old.rb +37 -0
  64. data/lib/support/to_discard/validations.rb +41 -0
  65. data/lib/support/to_discard/validations_conditional.rb +146 -0
  66. data/lib/support/trace_debug_lines.txt +319 -0
  67. data/lib/support/util.rb +15 -0
  68. data/lib/templates/controller/action_controller/controller_spec_template.haml +146 -0
  69. data/lib/templates/factory/active_record/factory_template.haml +13 -0
  70. data/lib/templates/model/active_record/model_spec_template.haml +233 -0
  71. data/lib/templates/shoulda_matchmakers.rb +112 -0
  72. metadata +263 -0
@@ -0,0 +1,16 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveModelMatcher
5
+ module ValidateAcceptanceOf
6
+
7
+ def validate_acceptance_of_matcher_tests
8
+ acceptance_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::AcceptanceValidator).flatten
9
+ generate_validator_matcher_tests(acceptance_validators)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveModelMatcher
5
+ module ValidateConfirmationOf
6
+
7
+ def validate_confirmation_of_matcher_tests
8
+ confirmation_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::ConfirmationValidator).flatten
9
+ generate_validator_matcher_tests(confirmation_validators)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,145 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module Matchmaker
5
+ module ValidateExclusionOf
6
+
7
+
8
+ def validate_exclusion_of_matcher_tests
9
+ exclusion_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::ExclusionValidator).flatten
10
+ if exclusion_validators.present?
11
+ generate_exclusion_validator_matcher_tests(exclusion_validators)
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+
18
+ private
19
+
20
+ def generate_exclusion_validator_matcher_tests(exclusion_validators)
21
+ exclusion_tests = []
22
+ exclusion_validators.map do |exclusion_validator|
23
+ if conditional_options_exist(exclusion_validator.options)
24
+ exclusion_tests = exclusion_tests + generate_exclusion_conditional_tests(exclusion_validator)
25
+ else
26
+ exclusion_tests << generate_exclusion_test(exclusion_validator, exclusion_validator.options)
27
+ end
28
+ end
29
+ exclusion_tests = properly_line_space_tests(exclusion_tests)
30
+ exclusion_tests.flatten.compact.uniq.join("\n")
31
+ end
32
+
33
+ def generate_exclusion_test(exclusion_validator, exclusion_options)
34
+ exclusion_test = get_exclusion_test_core(exclusion_options, exclusion_validator.attributes[0])
35
+ exclusion_options_string = get_options_string(exclusion_options)
36
+ exclusion_options_string = exclusion_options_string.gsub(".", ".\n ")
37
+ exclusion_test.concat(exclusion_options_string + "\n end")
38
+ exclusion_test
39
+ end
40
+
41
+ def generate_exclusion_conditional_tests(exclusion_validator)
42
+ exclusion_conditional_tests = []
43
+ exclusion_options = parse_validator_options(exclusion_validator.options.dup)
44
+ if all_option_values_are_symbols(exclusion_options[:if_option_values]) &&
45
+ all_option_values_are_symbols(exclusion_options[:unless_option_values])
46
+ exclusion_conditional_tests << generate_exclusion_validating_test(exclusion_validator, exclusion_options[:non_conditional_options])
47
+ exclusion_conditional_tests = exclusion_conditional_tests + generate_exclusion_non_validating_tests(exclusion_validator, exclusion_options[:non_conditional_options])
48
+ # else
49
+ # Skip tests due to non-symbol conditions (see below)
50
+ end
51
+ exclusion_conditional_tests
52
+ end
53
+
54
+ def generate_exclusion_validating_test(exclusion_validator, exclusion_options)
55
+ exclusion_validating_test = compose_conditional_validating_context_string(exclusion_options)
56
+ validating_permutation = get_validating_true_false_permutation(exclusion_options)
57
+ exclusion_validating_test.concat(compose_conditional_before_strings(exclusion_options, validating_permutation))
58
+ validating_test = generate_exclusion_test(exclusion_validator, exclusion_options[:non_conditional_options])
59
+ validating_test = adjust_conditional_test_indentation(validating_test)
60
+ exclusion_validating_test.concat(validating_test + "\n end")
61
+ end
62
+
63
+ def generate_exclusion_non_validating_tests(exclusion_validator, exclusion_options)
64
+ exclusion_non_validating_tests = []
65
+ possible_conditional_permutations = get_possible_true_false_permutations(exclusion_options)
66
+ validating_permutation = get_validating_true_false_permutation(exclusion_options)
67
+ non_validating_permutations = possible_conditional_permutations - [validating_permutation]
68
+ non_validating_permutations.each do |non_validating_permutation|
69
+ exclusion_non_validating_test = generate_exclusion_non_validating_test(exclusion_validator, exclusion_options, non_validating_permutation)
70
+ exclusion_non_validating_tests << exclusion_non_validating_test
71
+ end
72
+ exclusion_non_validating_tests[0] = exclusion_non_validating_tests[0].prepend("#\n# For more natural readability of 'is_expected.not_to' context lines, 'unless' is represented by 'if not'\n# and 'unless not' is represented by 'if'.\n#\n")
73
+ exclusion_non_validating_tests
74
+ end
75
+
76
+ def generate_exclusion_non_validating_test(exclusion_validator, exclusion_options, non_validating_permutation)
77
+ exclusion_non_validating_test = compose_conditional_non_validating_context_string(exclusion_options, non_validating_permutation)
78
+ exclusion_non_validating_test.concat(compose_conditional_before_strings(exclusion_options, non_validating_permutation))
79
+ non_validating_test = generate_exclusion_test(exclusion_validator, exclusion_options[:non_conditional_options])
80
+ non_validating_test.sub!("is_expected.to","is_expected.not_to")
81
+ non_validating_test = adjust_conditional_test_indentation(non_validating_test)
82
+ exclusion_non_validating_test.concat(non_validating_test)
83
+ exclusion_non_validating_test.concat("\n end")
84
+ end
85
+
86
+ def get_exclusion_test_core(validator_options, validator_attribute)
87
+ exclusion_enumerable = validator_options[:in] || validator_options[:within]
88
+ if exclusion_enumerable.is_a?(Array)
89
+ " it do\n is_expected.to validate_exclusion_of(:#{ validator_attribute }).\n in_array(#{ exclusion_enumerable })"
90
+ elsif exclusion_enumerable.is_a?(Range)
91
+ " it do\n is_expected.to validate_exclusion_of(:#{ validator_attribute }).\n in_range(#{ exclusion_enumerable })"
92
+ elsif exclusion_enumerable.lambda?
93
+ " #\n # Note: Your 'in:/within:' configuration option value is a 'Lambda'\n" +
94
+ " # You will need to implement a customized test.\n" +
95
+ " it do\n skip(\"Remove this skip line once test customization has been implemented.\")\n is_expected.to validate_exclusion_of(:#{ validator_attribute })"
96
+ # CONFIRMATION TODO: Confirm whether or not exclusion_enumerable could be a 'Proc' that isn't a 'lambda'
97
+ elsif exclusion_enumerable.respond_to?(:call)
98
+ " #\n # Note: Your 'in:/within:' configuration option value is a 'Proc'\n" +
99
+ " # You will need to implement a customized test.\n" +
100
+ " it do\n skip(\"Remove this skip line once test customization has been implemented.\")\n is_expected.to validate_exclusion_of(:#{ validator_attribute })"
101
+ else
102
+ " #\n # Alert: Invalid 'in:/within:' enumerable object type: '#{ exclusion_enumerable.class.to_s }'\n" +
103
+ " # Valid exclusion 'in:/within:' enumerable object types: 'Array', 'Range'\n" +
104
+ " # (or a proc, lambda or symbol which returns an enumerable)\n" +
105
+ " it do\n skip(\"Remove this skip line once valid enumerable object type is provided.\")\n is_expected.to validate_exclusion_of(:#{ validator_attribute })"
106
+ end
107
+ end
108
+
109
+
110
+ # def get_exclusion_test_options(options)
111
+ # exclusion_test_options = ""
112
+ # options.map do |option, option_value|
113
+ # exclusion_test_option = get_exclusion_test_option(option, option_value)
114
+ # exclusion_test_options.concat(".\n " + exclusion_test_option) if exclusion_test_option.present?
115
+ # end
116
+ # exclusion_test_options
117
+ # end
118
+ #
119
+ # def get_exclusion_test_option(option, option_value)
120
+ # case option
121
+ # # IMPLEMENTATION TODO: Determine if 'allow_blank' is a valid option
122
+ # # when :allow_blank
123
+ # # "allow_blank"
124
+ # # IMPLEMENTATION TODO: Determine if 'allow_nil' is a valid option
125
+ # # when :allow_nil
126
+ # # "allow_nil"
127
+ # when :message
128
+ # if option_value.include? '"'
129
+ # "with_message('#{ option_value }')"
130
+ # else
131
+ # "with_message(\"#{ option_value }\")"
132
+ # end
133
+ # when :on
134
+ # "on(:#{ option_value })"
135
+ # else
136
+ # # IMPLEMENTATION TODO: Possibly handle as an error or modify evaluation of option
137
+ # ""
138
+ # end
139
+ # end
140
+
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,94 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module Matchmaker
5
+ module ValidateInclusionOf
6
+
7
+
8
+ def validate_inclusion_of_matcher_tests
9
+ inclusion_tests = []
10
+ extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::InclusionValidator).flatten.map do |validator|
11
+ validator_options = validator.options.dup
12
+ validator_if_option = validator_options.delete(:if)
13
+ validator_unless_option = validator_options.delete(:unless)
14
+ validator.attributes.map do |attribute|
15
+ inclusion_tests << generate_inclusion_test_multiple_lines(validator_options, attribute)
16
+ end
17
+ end
18
+ inclusion_tests.flatten.compact.uniq.join("\n\n")
19
+ end
20
+
21
+
22
+ private
23
+
24
+ def generate_inclusion_test_multiple_lines(validator_options, attribute)
25
+ inclusion_test = get_inclusion_test_core(validator_options, attribute)
26
+ inclusion_test_options = get_inclusion_test_options(validator_options)
27
+ inclusion_test.concat(inclusion_test_options) if inclusion_test_options.present?
28
+ inclusion_test.concat("\n end")
29
+ [inclusion_test]
30
+ end
31
+
32
+
33
+ def get_inclusion_test_core(validator_options, attribute)
34
+ inclusion_enumerable = validator_options[:in] || validator_options[:within]
35
+ if inclusion_enumerable.is_a?(Array)
36
+ " it do\n is_expected.to validate_inclusion_of(:#{ attribute }).\n in_array(#{ inclusion_enumerable })"
37
+ elsif inclusion_enumerable.is_a?(Range)
38
+ " it do\n is_expected.to validate_inclusion_of(:#{ attribute }).\n in_range(#{ inclusion_enumerable })"
39
+ elsif inclusion_enumerable.lambda?
40
+ " #\n # Note: Your 'in:/within:' configuration option value is a 'Lambda'\n" +
41
+ " # You will need to implement a customized test.\n" +
42
+ " it do\n skip(\"Remove this skip line once test customization has been implemented.\")\n is_expected.to validate_inclusion_of(:#{ attribute })"
43
+ # CONFIRMATION TODO: Confirm whether or not inclusion_enumerable could be a 'Proc' that isn't a 'lambda'
44
+ elsif inclusion_enumerable.respond_to?(:call)
45
+ " #\n # Note: Your 'in:/within:' configuration option value is a 'Proc'\n" +
46
+ " # You will need to implement a customized test.\n" +
47
+ " it do\n skip(\"Remove this skip line once test customization has been implemented.\")\n is_expected.to validate_inclusion_of(:#{ attribute })"
48
+ else
49
+ " #\n # Alert: Invalid 'in:/within:' enumerable object type: '#{ inclusion_enumerable.class.to_s }'\n" +
50
+ " # Valid inclusion 'in:/within:' enumerable object types: 'Array', 'Range'\n" +
51
+ " # (or a proc, lambda or symbol which returns an enumerable)\n" +
52
+ " it do\n skip(\"Remove this skip line once valid enumerable object type is provided.\")\n is_expected.to validate_inclusion_of(:#{ attribute })"
53
+ end
54
+ end
55
+
56
+
57
+ def get_inclusion_test_options(options)
58
+ inclusion_test_options = ""
59
+ options.map do |option, option_value|
60
+ inclusion_test_option = get_inclusion_test_option(option, option_value)
61
+ inclusion_test_options.concat(".\n " + inclusion_test_option) if inclusion_test_option.present?
62
+ end
63
+ inclusion_test_options
64
+ end
65
+
66
+
67
+ def get_inclusion_test_option(option, option_value)
68
+ # IMPLEMENTATION TODO: Determine if it is possible to implement 'with_low_message' and 'with_high_message'
69
+ case option
70
+ # IMPLEMENTATION TODO: Determine if 'allow_blank' is a valid option
71
+ # when :allow_blank
72
+ # "allow_blank"
73
+ # IMPLEMENTATION TODO: Determine if 'allow_nil' is a valid option
74
+ # when :allow_nil
75
+ # "allow_nil"
76
+ when :message
77
+ if option_value.include? '"'
78
+ "with_message('#{ option_value }')"
79
+ else
80
+ "with_message(\"#{ option_value }\")"
81
+ end
82
+ when :on
83
+ "on(:#{ option_value })"
84
+ else
85
+ # IMPLEMENTATION TODO: Possibly handle as an error or modify evaluation of option
86
+ ""
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,16 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveModelMatcher
5
+ module ValidateLengthOf
6
+
7
+ def validate_length_of_matcher_tests
8
+ length_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::LengthValidator).flatten
9
+ generate_validator_matcher_tests(length_validators)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveModelMatcher
5
+ module ValidateNumericalityOf
6
+
7
+ def validate_numericality_of_matcher_tests
8
+ numericality_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::NumericalityValidator).flatten
9
+ generate_validator_matcher_tests(numericality_validators)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveModelMatcher
5
+ module ValidatePresenceOf
6
+
7
+ def validate_presence_of_matcher_tests
8
+ presence_validators = extract_validators(@active_record_model_sm_model, ::ActiveRecord::Validations::PresenceValidator).flatten
9
+ generate_validator_matcher_tests(presence_validators)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveRecordMatcher
5
+ module ValidateUniquenessOf
6
+
7
+ def validate_uniqueness_of_matcher_tests
8
+ uniqueness_validators = extract_validators(@active_record_model_sm_model, ::ActiveRecord::Validations::UniquenessValidator).flatten
9
+ generate_validator_matcher_tests(uniqueness_validators)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module Validation
5
+
6
+ def wrap_conditional_validations validator, specs
7
+ # if_mock = if_condition_mock validator
8
+ # unless_mock = unless_condition_mock validator
9
+ # padding = if_mock.blank? && unless_mock.blank? ? '' : ' '
10
+ specs = specs.map do |spec|
11
+ "#{spec}"
12
+ # "#{padding}#{spec}"
13
+ end.uniq.join("\n")
14
+ # end.uniq.join("\n ")
15
+ # if if_mock.blank? && unless_mock.blank?
16
+ # specs
17
+ # else
18
+ # "context \"with conditions\" do\n before do\n#{if_mock}#{unless_mock} end\n\n#{specs}\n end\n"
19
+ # end
20
+ end
21
+
22
+ def if_condition_mock validator
23
+ if_condition = validator.options[:if]
24
+ return '' unless if_condition && if_condition.is_a?(Symbol)
25
+ " allow(subject).to receive(:#{if_condition.to_s}).and_return(true)\n"
26
+ end
27
+
28
+ def unless_condition_mock validator
29
+ unless_condition = validator.options[:unless]
30
+ return '' unless unless_condition && unless_condition.is_a?(Symbol)
31
+ " allow(subject).to receive(:#{unless_condition.to_s}).and_return(false)\n"
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,41 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ActiveModelMatcher
5
+ module Validations
6
+
7
+ def validate_absence_of_matcher_tests
8
+ absence_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::AbsenceValidator).flatten
9
+ generate_validator_matcher_tests(absence_validators)
10
+ end
11
+
12
+ def validate_acceptance_of_matcher_tests
13
+ acceptance_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::AcceptanceValidator).flatten
14
+ generate_validator_matcher_tests(acceptance_validators)
15
+ end
16
+
17
+ def validate_confirmation_of_matcher_tests
18
+ confirmation_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::ConfirmationValidator).flatten
19
+ generate_validator_matcher_tests(confirmation_validators)
20
+ end
21
+
22
+ def validate_length_of_matcher_tests
23
+ length_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::LengthValidator).flatten
24
+ generate_validator_matcher_tests(length_validators)
25
+ end
26
+
27
+ def validate_numericality_of_matcher_tests
28
+ numericality_validators = extract_validators(@active_record_model_sm_model, ::ActiveModel::Validations::NumericalityValidator).flatten
29
+ generate_validator_matcher_tests(numericality_validators)
30
+ end
31
+
32
+ def validate_presence_of_matcher_tests
33
+ presence_validators = extract_validators(@active_record_model_sm_model, ::ActiveRecord::Validations::PresenceValidator).flatten
34
+ generate_validator_matcher_tests(presence_validators)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,146 @@
1
+ module ShouldaMatchmakers
2
+ module Model
3
+ module ActiveRecord
4
+ module ConditionalValidations
5
+
6
+ # def generate_validation_tests(validator)
7
+ #
8
+ # end
9
+
10
+ def generate_conditional_validation_tests(validator)
11
+ validator_conditional_tests = []
12
+ if_option_values_are_symbols = true
13
+ unless_option_values_are_symbols = true
14
+ validator_options = validator.options.dup
15
+ if_option_values = validator_options.delete(:if)
16
+ unless_option_values = validator_options.delete(:unless)
17
+
18
+ if if_option_values.present?
19
+ if !if_option_values.is_a?(Array)
20
+ if_option_values = [if_option_values]
21
+ end
22
+ if_option_values_are_symbols = all_option_values_are_symbols(if_option_values)
23
+ else
24
+ if_option_values = []
25
+ end
26
+
27
+ if unless_option_values.present?
28
+ if !unless_option_values.is_a?(Array)
29
+ unless_option_values = [unless_option_values]
30
+ end
31
+ unless_option_values_are_symbols = all_option_values_are_symbols(unless_option_values)
32
+ else
33
+ unless_option_values = []
34
+ end
35
+
36
+ if if_option_values_are_symbols && unless_option_values_are_symbols
37
+
38
+ if_and_unless_option_values = if_option_values + unless_option_values
39
+ validator_conditional_test = " context \""
40
+
41
+ if_and_unless_option_values.each_with_index do |option_value, index|
42
+
43
+ if index < if_option_values.size
44
+ validator_conditional_test.concat("if #{ option_value.to_s.chomp('?')} and ")
45
+ else
46
+ validator_conditional_test.concat("unless #{ option_value.to_s.chomp('?')} and ")
47
+ end
48
+ end
49
+
50
+ validator_conditional_test.chomp!(" and ").concat("\" do\n")
51
+
52
+ if_and_unless_option_values.each_with_index do |option_value, index|
53
+ if index < if_option_values.size
54
+ validator_conditional_test.concat(" before { allow(subject).to receive(:#{ option_value }).and_return(true) }\n")
55
+ else
56
+ validator_conditional_test.concat(" before { allow(subject).to receive(:#{ option_value }).and_return(false) }\n")
57
+ end
58
+ end
59
+
60
+ validator_conditional_test.concat("\n it { is_expected.to validate_#{ validator.kind.to_s }_of(:#{ validator.attributes.first }) }\n end")
61
+ validator_conditional_tests << [validator_conditional_test]
62
+
63
+ possible_conditional_permutations = get_possible_permutations(if_option_values.size + unless_option_values.size)
64
+ validating_permutation = get_validating_permutation(if_option_values.size, unless_option_values.size)
65
+ non_validating_permutations = possible_conditional_permutations - [validating_permutation]
66
+
67
+ non_validating_permutations.each do |non_validating_permutation|
68
+ validator_conditional_test = " context \""
69
+
70
+ if_and_unless_option_values.each_with_index do |option_value, index|
71
+
72
+ if index < if_option_values.size
73
+ if non_validating_permutation[index]
74
+ # TRACE.debug " *** TRUE CLASS WORKED!!!"
75
+ end
76
+ if non_validating_permutation[index]
77
+ validator_conditional_test.concat("if #{ option_value.to_s.chomp('?')} and ")
78
+ else
79
+ validator_conditional_test.concat("if not #{ option_value.to_s.chomp('?')} and ")
80
+ end
81
+ else
82
+ if non_validating_permutation[index]
83
+ validator_conditional_test.concat("if #{ option_value.to_s.chomp('?')} and ")
84
+ else
85
+ validator_conditional_test.concat("if not #{ option_value.to_s.chomp('?')} and ")
86
+ end
87
+ end
88
+ end
89
+ validator_conditional_test.chomp!(" and ").concat("\" do\n")
90
+ if_and_unless_option_values.each_with_index do |option_value, index|
91
+ validator_conditional_test.concat(" before { allow(subject).to receive(:#{ option_value }).and_return(#{ non_validating_permutation[index] }) }\n")
92
+ end
93
+ validator_conditional_test.concat("\n it { is_expected.not_to validate_#{ validator.kind.to_s }_of(:#{ validator.attributes.first }) }\n end")
94
+ validator_conditional_tests << [validator_conditional_test]
95
+ end
96
+ # else
97
+ # Skip tests due to non-symbol conditions
98
+ # validator.attributes.map do |attribute|
99
+ # skip = true
100
+ # presence_test = generate_presence_test_single_line(validator_options, attribute, skip)
101
+ # if presence_test[0].length > 80 || validator_options.count > 1
102
+ # presence_test = generate_presence_test_multiple_lines(validator_options, attribute, skip)
103
+ # end
104
+ # presence_test_comment = " # This test is currently skipped due to if: and/or unless: conditions that aren't symbols.\n"
105
+ # presence_test_comment.concat(" # Provide ")
106
+ # presence_test.prepend(presence_test_comment)
107
+ # presence_tests << presence_test
108
+ # end
109
+ end
110
+ validator_conditional_tests
111
+ end
112
+
113
+
114
+ private
115
+
116
+ def all_option_values_are_symbols(option_values)
117
+ option_values_are_symbols = true
118
+ option_values.each do |option_value|
119
+ if !option_value.is_a?(Symbol)
120
+ option_values_are_symbols = false
121
+ end
122
+ end
123
+ option_values_are_symbols
124
+ end
125
+
126
+
127
+ def get_possible_permutations(number_of_option_values)
128
+ [true, false].repeated_permutation(number_of_option_values).to_a
129
+ end
130
+
131
+
132
+ def get_validating_permutation(if_option_values_size, unless_options_values_size)
133
+ validating_permutation = []
134
+ if_option_values_size.times do |n|
135
+ validating_permutation << true
136
+ end
137
+ unless_options_values_size.times do |n|
138
+ validating_permutation << false
139
+ end
140
+ validating_permutation
141
+ end
142
+
143
+ end
144
+ end
145
+ end
146
+ end