shoulda_matchmakers 0.1.0

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