ultra-fast-box 0.0.1

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 (140) hide show
  1. checksums.yaml +7 -0
  2. data/shoulda-matchers-8.0.1/LICENSE +22 -0
  3. data/shoulda-matchers-8.0.1/README.md +567 -0
  4. data/shoulda-matchers-8.0.1/docs/errors/NonCaseSwappableValueError.md +111 -0
  5. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/callback_matcher.rb +121 -0
  6. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +70 -0
  7. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/flash_store.rb +86 -0
  8. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/permit_matcher.rb +445 -0
  9. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +96 -0
  10. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_template_matcher.rb +84 -0
  11. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +145 -0
  12. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +115 -0
  13. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +148 -0
  14. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_matcher.rb +207 -0
  15. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_params.rb +62 -0
  16. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/session_store.rb +34 -0
  17. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +228 -0
  18. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_matcher.rb +163 -0
  19. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +107 -0
  20. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller.rb +24 -0
  21. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
  22. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
  23. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +232 -0
  24. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
  25. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
  26. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
  27. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
  28. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
  29. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher.rb +695 -0
  30. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/comparison_matcher.rb +157 -0
  31. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +78 -0
  32. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/errors.rb +52 -0
  33. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +125 -0
  34. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/helpers.rb +37 -0
  35. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +45 -0
  36. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +67 -0
  37. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +45 -0
  38. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +44 -0
  39. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
  40. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +53 -0
  41. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  42. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
  43. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
  44. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
  45. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
  46. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers.rb +14 -0
  47. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +180 -0
  48. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +128 -0
  49. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +567 -0
  50. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +185 -0
  51. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +272 -0
  52. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +664 -0
  53. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +575 -0
  54. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +711 -0
  55. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +428 -0
  56. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +62 -0
  57. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher.rb +195 -0
  58. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_message_finder.rb +63 -0
  59. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validator.rb +127 -0
  60. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model.rb +96 -0
  61. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +217 -0
  62. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matcher.rb +2134 -0
  63. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +74 -0
  64. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +62 -0
  65. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +41 -0
  66. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +105 -0
  67. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +101 -0
  68. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +89 -0
  69. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +142 -0
  70. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +71 -0
  71. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
  72. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +76 -0
  73. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +42 -0
  74. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +65 -0
  75. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  76. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +784 -0
  77. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
  78. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_attached_matcher.rb +343 -0
  79. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +366 -0
  80. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +287 -0
  81. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +104 -0
  82. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +95 -0
  83. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
  84. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
  85. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
  86. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/serialize_matcher.rb +203 -0
  87. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/model.rb +58 -0
  88. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/namespace.rb +39 -0
  89. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +49 -0
  90. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +55 -0
  91. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness.rb +14 -0
  92. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +1197 -0
  93. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record.rb +37 -0
  94. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/configuration.rb +31 -0
  95. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double.rb +103 -0
  96. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_collection.rb +60 -0
  97. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +31 -0
  98. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/method_call.rb +44 -0
  99. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/object_double.rb +43 -0
  100. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +32 -0
  101. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/stub_implementation.rb +31 -0
  102. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/world.rb +63 -0
  103. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak.rb +38 -0
  104. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/error.rb +29 -0
  105. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +15 -0
  106. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher.rb +540 -0
  107. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent.rb +11 -0
  108. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration.rb +70 -0
  109. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration_error.rb +9 -0
  110. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/inclusion.rb +20 -0
  111. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/action_controller.rb +33 -0
  112. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_model.rb +26 -0
  113. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_record.rb +26 -0
  114. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/missing_library.rb +19 -0
  115. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/rails.rb +31 -0
  116. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/routing.rb +29 -0
  117. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries.rb +16 -0
  118. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/rails.rb +12 -0
  119. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/registry.rb +28 -0
  120. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +37 -0
  121. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +36 -0
  122. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +37 -0
  123. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +40 -0
  124. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +29 -0
  125. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +36 -0
  126. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks.rb +16 -0
  127. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations.rb +43 -0
  128. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_collection.rb +99 -0
  129. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_context.rb +36 -0
  130. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/rails_shim.rb +190 -0
  131. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/routing.rb +10 -0
  132. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util/word_wrap.rb +211 -0
  133. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util.rb +110 -0
  134. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/version.rb +6 -0
  135. data/shoulda-matchers-8.0.1/lib/shoulda/matchers/warn.rb +28 -0
  136. data/shoulda-matchers-8.0.1/lib/shoulda/matchers.rb +25 -0
  137. data/shoulda-matchers-8.0.1/lib/shoulda-matchers.rb +1 -0
  138. data/shoulda-matchers-8.0.1/shoulda-matchers.gemspec +43 -0
  139. data/ultra-fast-box.gemspec +12 -0
  140. metadata +179 -0
@@ -0,0 +1,157 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module Shoulda
4
+ module Matchers
5
+ module ActiveModel
6
+ # @private
7
+ class ComparisonMatcher < ValidationMatcher
8
+ ERROR_MESSAGES = {
9
+ :> => {
10
+ label: :greater_than,
11
+ assertions: [false, false, true],
12
+ },
13
+ :>= => {
14
+ label: :greater_than_or_equal_to,
15
+ assertions: [false, true, true],
16
+ },
17
+ :< => {
18
+ label: :less_than,
19
+ assertions: [true, false, false],
20
+ },
21
+ :<= => {
22
+ label: :less_than_or_equal_to,
23
+ assertions: [true, true, false],
24
+ },
25
+ :== => {
26
+ label: :equal_to,
27
+ assertions: [false, true, false],
28
+ },
29
+ :!= => {
30
+ label: :other_than,
31
+ assertions: [true, false, true],
32
+ },
33
+ }.freeze
34
+
35
+ delegate :failure_message, :failure_message_when_negated, to: :comparison_submatchers
36
+
37
+ def initialize(matcher, value, operator)
38
+ super(nil)
39
+ unless matcher.respond_to? :diff_to_compare
40
+ raise ArgumentError, 'matcher is invalid'
41
+ end
42
+
43
+ @matcher = matcher
44
+ @value = value
45
+ @operator = operator
46
+ @message = ERROR_MESSAGES[operator][:label]
47
+ end
48
+
49
+ def simple_description
50
+ description = ''
51
+
52
+ if expects_strict?
53
+ description = ' strictly'
54
+ end
55
+
56
+ description +
57
+ "disallow :#{attribute} from being a number that is not " +
58
+ "#{comparison_expectation} #{@value}"
59
+ end
60
+
61
+ def for(attribute)
62
+ @attribute = attribute
63
+ self
64
+ end
65
+
66
+ def with_message(message)
67
+ @expects_custom_validation_message = true
68
+ @message = message
69
+ self
70
+ end
71
+
72
+ def expects_custom_validation_message?
73
+ @expects_custom_validation_message
74
+ end
75
+
76
+ def matches?(subject)
77
+ @subject = subject
78
+ comparison_submatchers.matches?(subject)
79
+ end
80
+
81
+ def comparison_description
82
+ "#{comparison_expectation} #{@value}"
83
+ end
84
+
85
+ def comparison_submatchers
86
+ @_comparison_submatchers ||=
87
+ NumericalityMatchers::Submatchers.new(build_comparison_submatchers)
88
+ end
89
+
90
+ private
91
+
92
+ def build_comparison_submatchers
93
+ comparison_combos.map do |diff, submatcher_method_name|
94
+ matcher = __send__(submatcher_method_name, diff, nil)
95
+ matcher.with_message(@message, values: { count: option_value })
96
+ matcher
97
+ end
98
+ end
99
+
100
+ def comparison_combos
101
+ diffs_to_compare.zip(submatcher_method_names)
102
+ end
103
+
104
+ def submatcher_method_names
105
+ assertions.map do |value|
106
+ if value
107
+ :allow_value_matcher
108
+ else
109
+ :disallow_value_matcher
110
+ end
111
+ end
112
+ end
113
+
114
+ def assertions
115
+ ERROR_MESSAGES[@operator][:assertions]
116
+ end
117
+
118
+ def option_value
119
+ if defined?(@_option_value)
120
+ @_option_value
121
+ else
122
+ @_option_value =
123
+ case @value
124
+ when Proc then @value.call(@subject)
125
+ when Symbol then @subject.send(@value)
126
+ else @value
127
+ end
128
+ end
129
+ end
130
+
131
+ def diffs_to_compare
132
+ diff_to_compare = @matcher.diff_to_compare
133
+ values = case option_value
134
+ when String then diffs_when_string(diff_to_compare)
135
+ else [-1, 0, 1].map { |sign| option_value + (diff_to_compare * sign) }
136
+ end
137
+
138
+ if @matcher.given_numeric_column?
139
+ values
140
+ else
141
+ values.map(&:to_s)
142
+ end
143
+ end
144
+
145
+ def diffs_when_string(diff_to_compare)
146
+ [-1, 0, 1].map do |sign|
147
+ option_value[0..-2] + (option_value[-1].ord + diff_to_compare * sign).chr
148
+ end
149
+ end
150
+
151
+ def comparison_expectation
152
+ ERROR_MESSAGES[@operator][:label].to_s.tr('_', ' ')
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,78 @@
1
+ require 'forwardable'
2
+
3
+ module Shoulda
4
+ module Matchers
5
+ module ActiveModel
6
+ # @private
7
+ class DisallowValueMatcher
8
+ extend Forwardable
9
+
10
+ def_delegators(
11
+ :allow_matcher,
12
+ :_after_setting_value,
13
+ :attribute_changed_value_message=,
14
+ :attribute_to_set,
15
+ :description,
16
+ :expects_strict?,
17
+ :failure_message_preface,
18
+ :failure_message_preface=,
19
+ :ignore_interference_by_writer,
20
+ :last_attribute_setter_used,
21
+ :last_value_set,
22
+ :model,
23
+ :simple_description,
24
+ :values_to_preset=,
25
+ )
26
+
27
+ def initialize(value)
28
+ @allow_matcher = AllowValueMatcher.new(value)
29
+ end
30
+
31
+ def matches?(subject)
32
+ allow_matcher.does_not_match?(subject)
33
+ end
34
+
35
+ def does_not_match?(subject)
36
+ allow_matcher.matches?(subject)
37
+ end
38
+
39
+ def for(attribute)
40
+ allow_matcher.for(attribute)
41
+ self
42
+ end
43
+
44
+ def on(context)
45
+ allow_matcher.on(context)
46
+ self
47
+ end
48
+
49
+ def with_message(message, options = {})
50
+ allow_matcher.with_message(message, options)
51
+ self
52
+ end
53
+
54
+ def strict(strict = true)
55
+ allow_matcher.strict(strict)
56
+ self
57
+ end
58
+
59
+ def ignoring_interference_by_writer(value = :always)
60
+ allow_matcher.ignoring_interference_by_writer(value)
61
+ self
62
+ end
63
+
64
+ def failure_message
65
+ allow_matcher.failure_message_when_negated
66
+ end
67
+
68
+ def failure_message_when_negated
69
+ allow_matcher.failure_message
70
+ end
71
+
72
+ protected
73
+
74
+ attr_reader :allow_matcher
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,52 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ # @private
5
+ class CouldNotDetermineValueOutsideOfArray < RuntimeError; end
6
+
7
+ # @private
8
+ class NonNullableBooleanError < Shoulda::Matchers::Error
9
+ def self.create(attribute)
10
+ super(attribute:)
11
+ end
12
+
13
+ attr_accessor :attribute
14
+
15
+ def message
16
+ <<-EOT.strip
17
+ You have specified that your model's #{attribute} should ensure inclusion of nil.
18
+ However, #{attribute} is a boolean column which does not allow null values.
19
+ Hence, this test will fail and there is no way to make it pass.
20
+ EOT
21
+ end
22
+ end
23
+
24
+ # @private
25
+ class CouldNotSetPasswordError < Shoulda::Matchers::Error
26
+ def self.create(model)
27
+ super(model:)
28
+ end
29
+
30
+ attr_accessor :model
31
+
32
+ def message
33
+ <<-EOT.strip
34
+ The validation failed because your #{model_name} model declares `has_secure_password`, and
35
+ `validate_presence_of` was called on a #{record_name} which has `password` already set to a value.
36
+ Please use a #{record_name} with an empty `password` instead.
37
+ EOT
38
+ end
39
+
40
+ private
41
+
42
+ def model_name
43
+ model.name
44
+ end
45
+
46
+ def record_name
47
+ model_name.humanize.downcase
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,125 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ # The `have_secure_password` matcher tests usage of the
5
+ # `has_secure_password` macro.
6
+ #
7
+ # #### Example
8
+ #
9
+ # class User
10
+ # include ActiveModel::Model
11
+ # include ActiveModel::SecurePassword
12
+ # attr_accessor :password
13
+ # attr_accessor :reset_password
14
+ #
15
+ # has_secure_password
16
+ # has_secure_password :reset_password
17
+ # end
18
+ #
19
+ # # RSpec
20
+ # RSpec.describe User, type: :model do
21
+ # it { should have_secure_password }
22
+ # it { should have_secure_password(:reset_password) }
23
+ # end
24
+ #
25
+ # # Minitest (Shoulda)
26
+ # class UserTest < ActiveSupport::TestCase
27
+ # should have_secure_password
28
+ # should have_secure_password(:reset_password)
29
+ # end
30
+ #
31
+ # @return [HaveSecurePasswordMatcher]
32
+ #
33
+ def have_secure_password(attr = :password)
34
+ HaveSecurePasswordMatcher.new(attr)
35
+ end
36
+
37
+ # @private
38
+ class HaveSecurePasswordMatcher
39
+ attr_reader :failure_message
40
+
41
+ CORRECT_PASSWORD = 'aBcDe12345'.freeze
42
+ INCORRECT_PASSWORD = 'password'.freeze
43
+
44
+ MESSAGES = {
45
+ authenticated_incorrect_password: 'expected %{subject} to not'\
46
+ ' authenticate an incorrect %{attribute}',
47
+ did_not_authenticate_correct_password: 'expected %{subject} to'\
48
+ ' authenticate the correct %{attribute}',
49
+ method_not_found: 'expected %{subject} to respond to %{methods}',
50
+ should_not_have_secure_password: 'expected %{subject} to'\
51
+ ' not %{description}!',
52
+ }.freeze
53
+
54
+ def initialize(attribute)
55
+ @attribute = attribute.to_sym
56
+ end
57
+
58
+ def description
59
+ "have a secure password, defined on #{@attribute} attribute"
60
+ end
61
+
62
+ def matches?(subject)
63
+ @subject = subject
64
+
65
+ if failure = validate
66
+ key, params = failure
67
+ @failure_message =
68
+ MESSAGES[key] % { subject: subject.class }.merge(params)
69
+ end
70
+
71
+ failure.nil?
72
+ end
73
+
74
+ def failure_message_when_negated
75
+ MESSAGES[:should_not_have_secure_password] %
76
+ { subject: @subject.class, description: }
77
+ end
78
+
79
+ protected
80
+
81
+ attr_reader :subject
82
+
83
+ def validate
84
+ missing_methods = expected_methods.reject do |m|
85
+ subject.respond_to?(m)
86
+ end
87
+
88
+ if missing_methods.present?
89
+ [:method_not_found, { methods: missing_methods.to_sentence }]
90
+ else
91
+ subject.send("#{@attribute}=", CORRECT_PASSWORD)
92
+ subject.send("#{@attribute}_confirmation=", CORRECT_PASSWORD)
93
+
94
+ if not subject.send(authenticate_method, CORRECT_PASSWORD)
95
+ [:did_not_authenticate_correct_password,
96
+ { attribute: @attribute },]
97
+ elsif subject.send(authenticate_method, INCORRECT_PASSWORD)
98
+ [:authenticated_incorrect_password, { attribute: @attribute }]
99
+ end
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def expected_methods
106
+ @_expected_methods ||= %I[
107
+ #{authenticate_method}
108
+ #{@attribute}=
109
+ #{@attribute}_confirmation=
110
+ #{@attribute}_digest
111
+ #{@attribute}_digest=
112
+ ]
113
+ end
114
+
115
+ def authenticate_method
116
+ if @attribute == :password
117
+ :authenticate
118
+ else
119
+ "authenticate_#{@attribute}".to_sym
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,37 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ # @private
5
+ module Helpers
6
+ def pretty_error_messages(object)
7
+ format_validation_errors(object.errors)
8
+ end
9
+
10
+ def format_validation_errors(errors, attr = nil)
11
+ list_items = errors.to_hash.keys.map do |attribute|
12
+ next if attr && attr.to_sym != attribute.to_sym
13
+
14
+ messages = errors[attribute]
15
+ "* #{attribute}: #{messages}"
16
+ end
17
+
18
+ list_items.join("\n")
19
+ end
20
+
21
+ def default_error_message(type, options = {})
22
+ model_name = options.delete(:model_name)
23
+ attribute = options.delete(:attribute)
24
+ instance = options.delete(:instance)
25
+
26
+ RailsShim.generate_validation_message(
27
+ instance,
28
+ attribute.to_sym,
29
+ type,
30
+ model_name,
31
+ options,
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ module NumericalityMatchers
5
+ # @private
6
+ class EvenNumberMatcher < NumericTypeMatcher
7
+ NON_EVEN_NUMBER_VALUE = 1
8
+
9
+ def simple_description
10
+ description = ''
11
+
12
+ if expects_strict?
13
+ description << 'strictly '
14
+ end
15
+
16
+ description +
17
+ "disallow :#{attribute} from being an odd number"
18
+ end
19
+
20
+ def allowed_type_adjective
21
+ 'even'
22
+ end
23
+
24
+ def diff_to_compare
25
+ 2
26
+ end
27
+
28
+ protected
29
+
30
+ def wrap_disallow_value_matcher(matcher)
31
+ matcher.with_message(:even)
32
+ end
33
+
34
+ def disallowed_value
35
+ if @numeric_type_matcher.given_numeric_column?
36
+ NON_EVEN_NUMBER_VALUE
37
+ else
38
+ NON_EVEN_NUMBER_VALUE.to_s
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,67 @@
1
+ require 'forwardable'
2
+
3
+ module Shoulda
4
+ module Matchers
5
+ module ActiveModel
6
+ module NumericalityMatchers
7
+ # @private
8
+ class NumericTypeMatcher
9
+ extend Forwardable
10
+
11
+ def_delegators(
12
+ :disallow_value_matcher,
13
+ :expects_custom_validation_message?,
14
+ :expects_strict?,
15
+ :failure_message,
16
+ :failure_message_when_negated,
17
+ :ignore_interference_by_writer,
18
+ :ignoring_interference_by_writer,
19
+ :matches?,
20
+ :does_not_match?,
21
+ :on,
22
+ :strict,
23
+ :with_message,
24
+ )
25
+
26
+ def initialize(numeric_type_matcher, attribute)
27
+ @numeric_type_matcher = numeric_type_matcher
28
+ @attribute = attribute
29
+ end
30
+
31
+ def allowed_type_name
32
+ 'number'
33
+ end
34
+
35
+ def allowed_type_adjective
36
+ ''
37
+ end
38
+
39
+ def diff_to_compare
40
+ raise NotImplementedError
41
+ end
42
+
43
+ protected
44
+
45
+ attr_reader :attribute
46
+
47
+ def wrap_disallow_value_matcher(_matcher)
48
+ raise NotImplementedError
49
+ end
50
+
51
+ def disallowed_value
52
+ raise NotImplementedError
53
+ end
54
+
55
+ private
56
+
57
+ def disallow_value_matcher
58
+ @_disallow_value_matcher ||= DisallowValueMatcher.new(disallowed_value).tap do |matcher|
59
+ matcher.for(attribute)
60
+ wrap_disallow_value_matcher(matcher)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,45 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ module NumericalityMatchers
5
+ # @private
6
+ class OddNumberMatcher < NumericTypeMatcher
7
+ NON_ODD_NUMBER_VALUE = 2
8
+
9
+ def simple_description
10
+ description = ''
11
+
12
+ if expects_strict?
13
+ description << 'strictly '
14
+ end
15
+
16
+ description +
17
+ "disallow :#{attribute} from being an even number"
18
+ end
19
+
20
+ def allowed_type_adjective
21
+ 'odd'
22
+ end
23
+
24
+ def diff_to_compare
25
+ 2
26
+ end
27
+
28
+ protected
29
+
30
+ def wrap_disallow_value_matcher(matcher)
31
+ matcher.with_message(:odd)
32
+ end
33
+
34
+ def disallowed_value
35
+ if @numeric_type_matcher.given_numeric_column?
36
+ NON_ODD_NUMBER_VALUE
37
+ else
38
+ NON_ODD_NUMBER_VALUE.to_s
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,44 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveModel
4
+ module NumericalityMatchers
5
+ # @private
6
+ class OnlyIntegerMatcher < NumericTypeMatcher
7
+ NON_INTEGER_VALUE = 0.1
8
+
9
+ def simple_description
10
+ description = ''
11
+
12
+ if expects_strict?
13
+ description << ' strictly'
14
+ end
15
+
16
+ description + "disallow :#{attribute} from being a decimal number"
17
+ end
18
+
19
+ def allowed_type_name
20
+ 'integer'
21
+ end
22
+
23
+ def diff_to_compare
24
+ 1
25
+ end
26
+
27
+ protected
28
+
29
+ def wrap_disallow_value_matcher(matcher)
30
+ matcher.with_message(:not_an_integer)
31
+ end
32
+
33
+ def disallowed_value
34
+ if @numeric_type_matcher.given_numeric_column?
35
+ NON_INTEGER_VALUE
36
+ else
37
+ NON_INTEGER_VALUE.to_s
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end