activesupport 7.0.6 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +847 -267
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +25 -5
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +242 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +128 -0
  13. data/lib/active_support/cache/file_store.rb +36 -9
  14. data/lib/active_support/cache/mem_cache_store.rb +84 -68
  15. data/lib/active_support/cache/memory_store.rb +75 -21
  16. data/lib/active_support/cache/null_store.rb +6 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +136 -131
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +21 -9
  20. data/lib/active_support/cache.rb +298 -246
  21. data/lib/active_support/callbacks.rb +44 -21
  22. data/lib/active_support/concern.rb +4 -2
  23. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  24. data/lib/active_support/concurrency/null_lock.rb +13 -0
  25. data/lib/active_support/configurable.rb +10 -0
  26. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  27. data/lib/active_support/core_ext/array.rb +0 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  29. data/lib/active_support/core_ext/date/conversions.rb +1 -0
  30. data/lib/active_support/core_ext/date.rb +0 -1
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  32. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  33. data/lib/active_support/core_ext/date_time.rb +0 -1
  34. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  35. data/lib/active_support/core_ext/enumerable.rb +3 -70
  36. data/lib/active_support/core_ext/erb/util.rb +196 -0
  37. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  38. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  39. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  40. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  41. data/lib/active_support/core_ext/module/delegation.rb +40 -11
  42. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  43. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  44. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  45. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  46. data/lib/active_support/core_ext/numeric.rb +0 -1
  47. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  48. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  49. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  50. data/lib/active_support/core_ext/object/json.rb +11 -3
  51. data/lib/active_support/core_ext/object/with.rb +44 -0
  52. data/lib/active_support/core_ext/object/with_options.rb +3 -3
  53. data/lib/active_support/core_ext/object.rb +1 -0
  54. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  55. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  56. data/lib/active_support/core_ext/pathname.rb +1 -0
  57. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  58. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  59. data/lib/active_support/core_ext/range.rb +1 -2
  60. data/lib/active_support/core_ext/securerandom.rb +24 -12
  61. data/lib/active_support/core_ext/string/filters.rb +20 -14
  62. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  63. data/lib/active_support/core_ext/string/output_safety.rb +38 -174
  64. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  65. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  66. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  67. data/lib/active_support/core_ext/time/zones.rb +4 -4
  68. data/lib/active_support/core_ext/time.rb +0 -1
  69. data/lib/active_support/current_attributes.rb +15 -6
  70. data/lib/active_support/deep_mergeable.rb +53 -0
  71. data/lib/active_support/dependencies/autoload.rb +17 -12
  72. data/lib/active_support/deprecation/behaviors.rb +55 -34
  73. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  74. data/lib/active_support/deprecation/deprecators.rb +104 -0
  75. data/lib/active_support/deprecation/disallowed.rb +3 -5
  76. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  77. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  78. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  79. data/lib/active_support/deprecation/reporting.rb +35 -21
  80. data/lib/active_support/deprecation.rb +32 -5
  81. data/lib/active_support/deprecator.rb +7 -0
  82. data/lib/active_support/descendants_tracker.rb +104 -132
  83. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  84. data/lib/active_support/duration.rb +2 -1
  85. data/lib/active_support/encrypted_configuration.rb +30 -9
  86. data/lib/active_support/encrypted_file.rb +16 -12
  87. data/lib/active_support/environment_inquirer.rb +22 -2
  88. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  89. data/lib/active_support/error_reporter.rb +121 -35
  90. data/lib/active_support/evented_file_update_checker.rb +3 -1
  91. data/lib/active_support/execution_wrapper.rb +4 -4
  92. data/lib/active_support/file_update_checker.rb +4 -2
  93. data/lib/active_support/fork_tracker.rb +10 -2
  94. data/lib/active_support/gem_version.rb +3 -3
  95. data/lib/active_support/gzip.rb +2 -0
  96. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  97. data/lib/active_support/i18n.rb +1 -1
  98. data/lib/active_support/i18n_railtie.rb +20 -13
  99. data/lib/active_support/inflector/inflections.rb +2 -0
  100. data/lib/active_support/inflector/methods.rb +23 -11
  101. data/lib/active_support/inflector/transliterate.rb +3 -1
  102. data/lib/active_support/isolated_execution_state.rb +26 -22
  103. data/lib/active_support/json/decoding.rb +2 -1
  104. data/lib/active_support/json/encoding.rb +25 -43
  105. data/lib/active_support/key_generator.rb +9 -1
  106. data/lib/active_support/lazy_load_hooks.rb +6 -4
  107. data/lib/active_support/locale/en.yml +2 -0
  108. data/lib/active_support/log_subscriber.rb +78 -33
  109. data/lib/active_support/logger.rb +9 -60
  110. data/lib/active_support/logger_thread_safe_level.rb +10 -24
  111. data/lib/active_support/message_encryptor.rb +197 -53
  112. data/lib/active_support/message_encryptors.rb +141 -0
  113. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  114. data/lib/active_support/message_pack/extensions.rb +292 -0
  115. data/lib/active_support/message_pack/serializer.rb +63 -0
  116. data/lib/active_support/message_pack.rb +50 -0
  117. data/lib/active_support/message_verifier.rb +212 -93
  118. data/lib/active_support/message_verifiers.rb +135 -0
  119. data/lib/active_support/messages/codec.rb +65 -0
  120. data/lib/active_support/messages/metadata.rb +111 -45
  121. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  122. data/lib/active_support/messages/rotator.rb +34 -32
  123. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  124. data/lib/active_support/multibyte/chars.rb +2 -0
  125. data/lib/active_support/multibyte/unicode.rb +9 -37
  126. data/lib/active_support/notifications/fanout.rb +239 -81
  127. data/lib/active_support/notifications/instrumenter.rb +77 -20
  128. data/lib/active_support/notifications.rb +1 -1
  129. data/lib/active_support/number_helper/number_converter.rb +14 -5
  130. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  131. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  132. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  133. data/lib/active_support/ordered_hash.rb +3 -3
  134. data/lib/active_support/ordered_options.rb +14 -0
  135. data/lib/active_support/parameter_filter.rb +84 -69
  136. data/lib/active_support/proxy_object.rb +2 -0
  137. data/lib/active_support/railtie.rb +33 -21
  138. data/lib/active_support/reloader.rb +12 -4
  139. data/lib/active_support/rescuable.rb +2 -0
  140. data/lib/active_support/secure_compare_rotator.rb +16 -9
  141. data/lib/active_support/string_inquirer.rb +3 -1
  142. data/lib/active_support/subscriber.rb +9 -27
  143. data/lib/active_support/syntax_error_proxy.rb +49 -0
  144. data/lib/active_support/tagged_logging.rb +60 -24
  145. data/lib/active_support/test_case.rb +153 -6
  146. data/lib/active_support/testing/assertions.rb +25 -9
  147. data/lib/active_support/testing/autorun.rb +0 -2
  148. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  149. data/lib/active_support/testing/deprecation.rb +25 -25
  150. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  151. data/lib/active_support/testing/isolation.rb +1 -1
  152. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  153. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  154. data/lib/active_support/testing/stream.rb +1 -1
  155. data/lib/active_support/testing/strict_warnings.rb +38 -0
  156. data/lib/active_support/testing/time_helpers.rb +32 -14
  157. data/lib/active_support/time_with_zone.rb +6 -35
  158. data/lib/active_support/values/time_zone.rb +9 -7
  159. data/lib/active_support/version.rb +1 -1
  160. data/lib/active_support/xml_mini/jdom.rb +3 -10
  161. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  162. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  163. data/lib/active_support/xml_mini/rexml.rb +1 -1
  164. data/lib/active_support/xml_mini.rb +2 -2
  165. data/lib/active_support.rb +14 -3
  166. metadata +106 -19
  167. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  168. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
  169. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
  170. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  171. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
  172. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  173. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  174. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
  175. data/lib/active_support/core_ext/uri.rb +0 -5
  176. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -6,14 +6,16 @@ require "logger"
6
6
  require "active_support/logger"
7
7
 
8
8
  module ActiveSupport
9
+ # = Active Support Tagged Logging
10
+ #
9
11
  # Wraps any standard Logger object to provide tagging capabilities.
10
12
  #
11
13
  # May be called with a block:
12
14
  #
13
15
  # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
14
- # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
15
- # logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
16
- # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
16
+ # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
17
+ # logger.tagged('BCX', "Jason") { |tagged_logger| tagged_logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
18
+ # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
17
19
  #
18
20
  # If called without a block, a new logger will be returned with applied tags:
19
21
  #
@@ -29,52 +31,86 @@ module ActiveSupport
29
31
  module Formatter # :nodoc:
30
32
  # This method is invoked when a log event occurs.
31
33
  def call(severity, timestamp, progname, msg)
32
- super(severity, timestamp, progname, "#{tags_text}#{msg}")
34
+ super(severity, timestamp, progname, tag_stack.format_message(msg))
33
35
  end
34
36
 
35
37
  def tagged(*tags)
36
- new_tags = push_tags(*tags)
38
+ pushed_count = tag_stack.push_tags(tags).size
37
39
  yield self
38
40
  ensure
39
- pop_tags(new_tags.size)
41
+ pop_tags(pushed_count)
40
42
  end
41
43
 
42
44
  def push_tags(*tags)
43
- tags.flatten!
44
- tags.reject!(&:blank?)
45
- current_tags.concat tags
46
- tags
45
+ tag_stack.push_tags(tags)
47
46
  end
48
47
 
49
- def pop_tags(size = 1)
50
- current_tags.pop size
48
+ def pop_tags(count = 1)
49
+ tag_stack.pop_tags(count)
51
50
  end
52
51
 
53
52
  def clear_tags!
54
- current_tags.clear
53
+ tag_stack.clear
55
54
  end
56
55
 
57
- def current_tags
56
+ def tag_stack
58
57
  # We use our object ID here to avoid conflicting with other instances
59
- thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
60
- IsolatedExecutionState[thread_key] ||= []
58
+ @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
59
+ IsolatedExecutionState[@thread_key] ||= TagStack.new
60
+ end
61
+
62
+ def current_tags
63
+ tag_stack.tags
61
64
  end
62
65
 
63
66
  def tags_text
64
- tags = current_tags
65
- if tags.one?
66
- "[#{tags[0]}] "
67
- elsif tags.any?
68
- tags.collect { |tag| "[#{tag}] " }.join
67
+ tag_stack.format_message("")
68
+ end
69
+ end
70
+
71
+ class TagStack # :nodoc:
72
+ attr_reader :tags
73
+
74
+ def initialize
75
+ @tags = []
76
+ @tags_string = nil
77
+ end
78
+
79
+ def push_tags(tags)
80
+ @tags_string = nil
81
+ tags.flatten!
82
+ tags.reject!(&:blank?)
83
+ @tags.concat(tags)
84
+ tags
85
+ end
86
+
87
+ def pop_tags(count)
88
+ @tags_string = nil
89
+ @tags.pop(count)
90
+ end
91
+
92
+ def clear
93
+ @tags_string = nil
94
+ @tags.clear
95
+ end
96
+
97
+ def format_message(message)
98
+ if @tags.empty?
99
+ message
100
+ elsif @tags.size == 1
101
+ "[#{@tags[0]}] #{message}"
102
+ else
103
+ @tags_string ||= "[#{@tags.join("] [")}] "
104
+ "#{@tags_string}#{message}"
69
105
  end
70
106
  end
71
107
  end
72
108
 
73
109
  module LocalTagStorage # :nodoc:
74
- attr_accessor :current_tags
110
+ attr_accessor :tag_stack
75
111
 
76
112
  def self.extended(base)
77
- base.current_tags = []
113
+ base.tag_stack = TagStack.new
78
114
  end
79
115
  end
80
116
 
@@ -82,7 +118,7 @@ module ActiveSupport
82
118
  logger = logger.clone
83
119
 
84
120
  if logger.formatter
85
- logger.formatter = logger.formatter.dup
121
+ logger.formatter = logger.formatter.clone
86
122
  else
87
123
  # Ensure we set a default formatter so we aren't extending nil!
88
124
  logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "minitest" # make sure we get the gem, not stdlib
4
3
  require "minitest"
5
4
  require "active_support/testing/tagged_logging"
6
5
  require "active_support/testing/setup_and_teardown"
7
6
  require "active_support/testing/assertions"
7
+ require "active_support/testing/error_reporter_assertions"
8
8
  require "active_support/testing/deprecation"
9
9
  require "active_support/testing/declarative"
10
10
  require "active_support/testing/isolation"
11
11
  require "active_support/testing/constant_lookup"
12
12
  require "active_support/testing/time_helpers"
13
+ require "active_support/testing/constant_stubbing"
13
14
  require "active_support/testing/file_fixtures"
14
15
  require "active_support/testing/parallelization"
15
16
  require "active_support/testing/parallelize_executor"
@@ -66,7 +67,7 @@ module ActiveSupport
66
67
  # The default parallelization method is to fork processes. If you'd like to
67
68
  # use threads instead you can pass <tt>with: :threads</tt> to the +parallelize+
68
69
  # method. Note the threaded parallelization does not create multiple
69
- # database and will not work with system tests at this time.
70
+ # databases and will not work with system tests.
70
71
  #
71
72
  # parallelize(workers: :number_of_processors, with: :threads)
72
73
  #
@@ -80,8 +81,6 @@ module ActiveSupport
80
81
  workers = Concurrent.physical_processor_count if workers == :number_of_processors
81
82
  workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
82
83
 
83
- return if workers <= 1
84
-
85
84
  Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
86
85
  end
87
86
 
@@ -118,6 +117,25 @@ module ActiveSupport
118
117
  def parallelize_teardown(&block)
119
118
  ActiveSupport::Testing::Parallelization.run_cleanup_hook(&block)
120
119
  end
120
+
121
+ # :singleton-method: fixture_paths
122
+ #
123
+ # Returns the ActiveRecord::FixtureSet collection.
124
+ #
125
+ # In your +test_helper.rb+ you must have <tt>require "rails/test_help"</tt>.
126
+
127
+ # :singleton-method: fixture_paths=
128
+ #
129
+ # :call-seq:
130
+ # fixture_paths=(fixture_paths)
131
+ #
132
+ # Sets the given path to the fixture set.
133
+ #
134
+ # Can also append multiple paths.
135
+ #
136
+ # ActiveSupport::TestCase.fixture_paths << "component1/test/fixtures"
137
+ #
138
+ # In your +test_helper.rb+ you must have <tt>require "rails/test_help"</tt>.
121
139
  end
122
140
 
123
141
  alias_method :method_name, :name
@@ -125,25 +143,154 @@ module ActiveSupport
125
143
  include ActiveSupport::Testing::TaggedLogging
126
144
  prepend ActiveSupport::Testing::SetupAndTeardown
127
145
  include ActiveSupport::Testing::Assertions
146
+ include ActiveSupport::Testing::ErrorReporterAssertions
128
147
  include ActiveSupport::Testing::Deprecation
148
+ include ActiveSupport::Testing::ConstantStubbing
129
149
  include ActiveSupport::Testing::TimeHelpers
130
150
  include ActiveSupport::Testing::FileFixtures
131
151
  extend ActiveSupport::Testing::Declarative
132
152
 
133
- # test/unit backwards compatibility methods
134
- alias :assert_raise :assert_raises
153
+ ##
154
+ # :method: assert_not_empty
155
+ #
156
+ # :call-seq:
157
+ # assert_not_empty(obj, msg = nil)
158
+ #
159
+ # Alias for: refute_empty[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_empty]
160
+
161
+ #
135
162
  alias :assert_not_empty :refute_empty
163
+
164
+ ##
165
+ # :method: assert_not_equal
166
+ #
167
+ # :call-seq:
168
+ # assert_not_equal(exp, act, msg = nil)
169
+ #
170
+ # Alias for: refute_equal[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_equal]
171
+
172
+ #
136
173
  alias :assert_not_equal :refute_equal
174
+
175
+ ##
176
+ # :method: assert_not_in_delta
177
+ #
178
+ # :call-seq:
179
+ # assert_not_in_delta(exp, act, delta = 0.001, msg = nil)
180
+ #
181
+ # Alias for: refute_in_delta[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_in_delta]
182
+
183
+ #
137
184
  alias :assert_not_in_delta :refute_in_delta
185
+
186
+ ##
187
+ # :method: assert_not_in_epsilon
188
+ #
189
+ # :call-seq:
190
+ # assert_not_in_epsilon(a, b, epsilon = 0.001, msg = nil)
191
+ #
192
+ # Alias for: refute_in_epsilon[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_in_epsilon]
193
+
194
+ #
138
195
  alias :assert_not_in_epsilon :refute_in_epsilon
196
+
197
+ ##
198
+ # :method: assert_not_includes
199
+ #
200
+ # :call-seq:
201
+ # assert_not_includes(collection, obj, msg = nil)
202
+ #
203
+ # Alias for: refute_includes[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_includes]
204
+
205
+ #
139
206
  alias :assert_not_includes :refute_includes
207
+
208
+ ##
209
+ # :method: assert_not_instance_of
210
+ #
211
+ # :call-seq:
212
+ # assert_not_instance_of(cls, obj, msg = nil)
213
+ #
214
+ # Alias for: refute_instance_of[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_instance_of]
215
+
216
+ #
140
217
  alias :assert_not_instance_of :refute_instance_of
218
+
219
+ ##
220
+ # :method: assert_not_kind_of
221
+ #
222
+ # :call-seq:
223
+ # assert_not_kind_of(cls, obj, msg = nil)
224
+ #
225
+ # Alias for: refute_kind_of[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_kind_of]
226
+
227
+ #
141
228
  alias :assert_not_kind_of :refute_kind_of
229
+
230
+ ##
231
+ # :method: assert_no_match
232
+ #
233
+ # :call-seq:
234
+ # assert_no_match(matcher, obj, msg = nil)
235
+ #
236
+ # Alias for: refute_match[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_match]
237
+
238
+ #
142
239
  alias :assert_no_match :refute_match
240
+
241
+ ##
242
+ # :method: assert_not_nil
243
+ #
244
+ # :call-seq:
245
+ # assert_not_nil(obj, msg = nil)
246
+ #
247
+ # Alias for: refute_nil[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_nil]
248
+
249
+ #
143
250
  alias :assert_not_nil :refute_nil
251
+
252
+ ##
253
+ # :method: assert_not_operator
254
+ #
255
+ # :call-seq:
256
+ # assert_not_operator(o1, op, o2 = UNDEFINED, msg = nil)
257
+ #
258
+ # Alias for: refute_operator[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_operator]
259
+
260
+ #
144
261
  alias :assert_not_operator :refute_operator
262
+
263
+ ##
264
+ # :method: assert_not_predicate
265
+ #
266
+ # :call-seq:
267
+ # assert_not_predicate(o1, op, msg = nil)
268
+ #
269
+ # Alias for: refute_predicate[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_predicate]
270
+
271
+ #
145
272
  alias :assert_not_predicate :refute_predicate
273
+
274
+ ##
275
+ # :method: assert_not_respond_to
276
+ #
277
+ # :call-seq:
278
+ # assert_not_respond_to(obj, meth, msg = nil)
279
+ #
280
+ # Alias for: refute_respond_to[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_respond_to]
281
+
282
+ #
146
283
  alias :assert_not_respond_to :refute_respond_to
284
+
285
+ ##
286
+ # :method: assert_not_same
287
+ #
288
+ # :call-seq:
289
+ # assert_not_same(exp, act, msg = nil)
290
+ #
291
+ # Alias for: refute_same[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_same]
292
+
293
+ #
147
294
  alias :assert_not_same :refute_same
148
295
 
149
296
  ActiveSupport.run_load_hooks(:active_support_test_case, self)
@@ -7,9 +7,9 @@ module ActiveSupport
7
7
  module Assertions
8
8
  UNTRACKED = Object.new # :nodoc:
9
9
 
10
- # Asserts that an expression is not truthy. Passes if <tt>object</tt> is
11
- # +nil+ or +false+. "Truthy" means "considered true in a conditional"
12
- # like <tt>if foo</tt>.
10
+ # Asserts that an expression is not truthy. Passes if +object+ is +nil+ or
11
+ # +false+. "Truthy" means "considered true in a conditional" like <tt>if
12
+ # foo</tt>.
13
13
  #
14
14
  # assert_not nil # => true
15
15
  # assert_not false # => true
@@ -23,6 +23,21 @@ module ActiveSupport
23
23
  assert !object, message
24
24
  end
25
25
 
26
+ # Asserts that a block raises one of +exp+. This is an enhancement of the
27
+ # standard Minitest assertion method with the ability to test error
28
+ # messages.
29
+ #
30
+ # assert_raises(ArgumentError, match: /incorrect param/i) do
31
+ # perform_service(param: 'exception')
32
+ # end
33
+ #
34
+ def assert_raises(*exp, match: nil, &block)
35
+ error = super(*exp, &block)
36
+ assert_match(match, error.message) if match
37
+ error
38
+ end
39
+ alias :assert_raise :assert_raises
40
+
26
41
  # Assertion that the block should not raise an exception.
27
42
  #
28
43
  # Passes if evaluated code in the yielded block raises no exception.
@@ -31,7 +46,7 @@ module ActiveSupport
31
46
  # perform_service(param: 'no_exception')
32
47
  # end
33
48
  def assert_nothing_raised
34
- yield
49
+ yield.tap { assert(true) }
35
50
  rescue => error
36
51
  raise Minitest::UnexpectedError.new(error)
37
52
  end
@@ -50,7 +65,7 @@ module ActiveSupport
50
65
  # end
51
66
  #
52
67
  # An arbitrary positive or negative difference can be specified.
53
- # The default is <tt>1</tt>.
68
+ # The default is +1+.
54
69
  #
55
70
  # assert_difference 'Article.count', -1 do
56
71
  # post :delete, params: { id: ... }
@@ -102,9 +117,10 @@ module ActiveSupport
102
117
  retval = _assert_nothing_raised_or_warn("assert_difference", &block)
103
118
 
104
119
  expressions.zip(exps, before) do |(code, diff), exp, before_value|
105
- error = "#{code.inspect} didn't change by #{diff}"
120
+ actual = exp.call
121
+ error = "#{code.inspect} didn't change by #{diff}, but by #{actual - before_value}"
106
122
  error = "#{message}.\n#{error}" if message
107
- assert_equal(before_value + diff, exp.call, error)
123
+ assert_equal(before_value + diff, actual, error)
108
124
  end
109
125
 
110
126
  retval
@@ -179,7 +195,7 @@ module ActiveSupport
179
195
  retval = _assert_nothing_raised_or_warn("assert_changes", &block)
180
196
 
181
197
  unless from == UNTRACKED
182
- error = "Expected change from #{from.inspect}"
198
+ error = "Expected change from #{from.inspect}, got #{before}"
183
199
  error = "#{message}.\n#{error}" if message
184
200
  assert from === before, error
185
201
  end
@@ -192,7 +208,7 @@ module ActiveSupport
192
208
  refute_equal before, after, error
193
209
 
194
210
  unless to == UNTRACKED
195
- error = "Expected change to #{to}\n"
211
+ error = "Expected change to #{to}, got #{after}\n"
196
212
  error = "#{message}.\n#{error}" if message
197
213
  assert to === after, error
198
214
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "minitest"
4
-
5
3
  require "minitest"
6
4
 
7
5
  Minitest.autorun
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module ConstantStubbing
6
+ # Changes the value of a constant for the duration of a block. Example:
7
+ #
8
+ # # World::List::Import::LARGE_IMPORT_THRESHOLD = 5000
9
+ # stub_const(World::List::Import, :LARGE_IMPORT_THRESHOLD, 1) do
10
+ # assert_equal 1, World::List::Import::LARGE_IMPORT_THRESHOLD
11
+ # end
12
+ #
13
+ # assert_equal 5000, World::List::Import::LARGE_IMPORT_THRESHOLD
14
+ #
15
+ # Using this method rather than forcing <tt>World::List::Import::LARGE_IMPORT_THRESHOLD = 5000</tt> prevents
16
+ # warnings from being thrown, and ensures that the old value is returned after the test has completed.
17
+ #
18
+ # Note: Stubbing a const will stub it across all threads. So if you have concurrent threads
19
+ # (like separate test suites running in parallel) that all depend on the same constant, it's possible
20
+ # divergent stubbing will trample on each other.
21
+ def stub_const(mod, constant, new_value)
22
+ old_value = mod.const_get(constant, false)
23
+ mod.send(:remove_const, constant)
24
+ mod.const_set(constant, new_value)
25
+ yield
26
+ ensure
27
+ mod.send(:remove_const, constant)
28
+ mod.const_set(constant, old_value)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -5,6 +5,11 @@ require "active_support/deprecation"
5
5
  module ActiveSupport
6
6
  module Testing
7
7
  module Deprecation
8
+ ##
9
+ # :call-seq:
10
+ # assert_deprecated(deprecator, &block)
11
+ # assert_deprecated(match, deprecator, &block)
12
+ #
8
13
  # Asserts that a matching deprecation warning was emitted by the given deprecator during the execution of the yielded block.
9
14
  #
10
15
  # assert_deprecated(/foo/, CustomDeprecator) do
@@ -19,16 +24,15 @@ module ActiveSupport
19
24
  #
20
25
  # If the +match+ is omitted (or explicitly +nil+), any deprecation warning will match.
21
26
  #
22
- # assert_deprecated(nil, CustomDeprecator) do
27
+ # assert_deprecated(CustomDeprecator) do
23
28
  # CustomDeprecator.warn "foo should no longer be used"
24
29
  # end
25
- #
26
- # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
27
- #
28
- # assert_deprecated do
29
- # ActiveSupport::Deprecation.warn "foo should no longer be used"
30
- # end
31
30
  def assert_deprecated(match = nil, deprecator = nil, &block)
31
+ match, deprecator = nil, match if match.is_a?(ActiveSupport::Deprecation)
32
+ unless deprecator
33
+ ActiveSupport.deprecator.warn("assert_deprecated without a deprecator is deprecated")
34
+ deprecator = ActiveSupport::Deprecation._instance
35
+ end
32
36
  result, warnings = collect_deprecations(deprecator, &block)
33
37
  assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
34
38
  if match
@@ -44,36 +48,32 @@ module ActiveSupport
44
48
  # CustomDeprecator.warn "message" # fails assertion
45
49
  # end
46
50
  #
47
- # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
48
- #
49
- # assert_not_deprecated do
50
- # ActiveSupport::Deprecation.warn "message" # fails assertion
51
- # end
52
- #
53
- # assert_not_deprecated do
54
- # CustomDeprecator.warn "message" # passes assertion
51
+ # assert_not_deprecated(ActiveSupport::Deprecation.new) do
52
+ # CustomDeprecator.warn "message" # passes assertion, different deprecator
55
53
  # end
56
54
  def assert_not_deprecated(deprecator = nil, &block)
55
+ unless deprecator
56
+ ActiveSupport.deprecator.warn("assert_not_deprecated without a deprecator is deprecated")
57
+ deprecator = ActiveSupport::Deprecation._instance
58
+ end
57
59
  result, deprecations = collect_deprecations(deprecator, &block)
58
60
  assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
59
61
  result
60
62
  end
61
63
 
62
- # Returns an array of all the deprecation warnings emitted by the given
64
+ # Returns the return value of the block and an array of all the deprecation warnings emitted by the given
63
65
  # +deprecator+ during the execution of the yielded block.
64
66
  #
65
67
  # collect_deprecations(CustomDeprecator) do
66
68
  # CustomDeprecator.warn "message"
67
- # end # => ["message"]
68
- #
69
- # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
70
- #
71
- # collect_deprecations do
72
- # CustomDeprecator.warn "custom message"
73
- # ActiveSupport::Deprecation.warn "message"
74
- # end # => ["message"]
69
+ # ActiveSupport::Deprecation.new.warn "other message"
70
+ # :result
71
+ # end # => [:result, ["message"]]
75
72
  def collect_deprecations(deprecator = nil)
76
- deprecator ||= ActiveSupport::Deprecation
73
+ unless deprecator
74
+ ActiveSupport.deprecator.warn("collect_deprecations without a deprecator is deprecated")
75
+ deprecator = ActiveSupport::Deprecation._instance
76
+ end
77
77
  old_behavior = deprecator.behavior
78
78
  deprecations = []
79
79
  deprecator.behavior = Proc.new do |message, callstack|
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module ErrorReporterAssertions
6
+ module ErrorCollector # :nodoc:
7
+ @subscribed = false
8
+ @mutex = Mutex.new
9
+
10
+ Report = Struct.new(:error, :handled, :severity, :context, :source, keyword_init: true)
11
+ class Report
12
+ alias_method :handled?, :handled
13
+ end
14
+
15
+ class << self
16
+ def record
17
+ subscribe
18
+ recorders = ActiveSupport::IsolatedExecutionState[:active_support_error_reporter_assertions] ||= []
19
+ reports = []
20
+ recorders << reports
21
+ begin
22
+ yield
23
+ reports
24
+ ensure
25
+ recorders.delete_if { |r| reports.equal?(r) }
26
+ end
27
+ end
28
+
29
+ def report(error, **kwargs)
30
+ report = Report.new(error: error, **kwargs)
31
+ ActiveSupport::IsolatedExecutionState[:active_support_error_reporter_assertions]&.each do |reports|
32
+ reports << report
33
+ end
34
+ true
35
+ end
36
+
37
+ private
38
+ def subscribe
39
+ return if @subscribed
40
+ @mutex.synchronize do
41
+ return if @subscribed
42
+
43
+ if ActiveSupport.error_reporter
44
+ ActiveSupport.error_reporter.subscribe(self)
45
+ @subscribed = true
46
+ else
47
+ raise Minitest::Assertion, "No error reporter is configured"
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ # Assertion that the block should not cause an exception to be reported
55
+ # to +Rails.error+.
56
+ #
57
+ # Passes if evaluated code in the yielded block reports no exception.
58
+ #
59
+ # assert_no_error_reported do
60
+ # perform_service(param: 'no_exception')
61
+ # end
62
+ def assert_no_error_reported(&block)
63
+ reports = ErrorCollector.record do
64
+ _assert_nothing_raised_or_warn("assert_no_error_reported", &block)
65
+ end
66
+ assert_predicate(reports, :empty?)
67
+ end
68
+
69
+ # Assertion that the block should cause at least one exception to be reported
70
+ # to +Rails.error+.
71
+ #
72
+ # Passes if the evaluated code in the yielded block reports a matching exception.
73
+ #
74
+ # assert_error_reported(IOError) do
75
+ # Rails.error.report(IOError.new("Oops"))
76
+ # end
77
+ #
78
+ # To test further details about the reported exception, you can use the return
79
+ # value.
80
+ #
81
+ # report = assert_error_reported(IOError) do
82
+ # # ...
83
+ # end
84
+ # assert_equal "Oops", report.error.message
85
+ # assert_equal "admin", report.context[:section]
86
+ # assert_equal :warning, report.severity
87
+ # assert_predicate report, :handled?
88
+ def assert_error_reported(error_class = StandardError, &block)
89
+ reports = ErrorCollector.record do
90
+ _assert_nothing_raised_or_warn("assert_error_reported", &block)
91
+ end
92
+
93
+ if reports.empty?
94
+ assert(false, "Expected a #{error_class.name} to be reported, but there were no errors reported.")
95
+ elsif (report = reports.find { |r| error_class === r.error })
96
+ self.assertions += 1
97
+ report
98
+ else
99
+ message = "Expected a #{error_class.name} to be reported, but none of the " \
100
+ "#{reports.size} reported errors matched: \n" \
101
+ "#{reports.map { |r| r.error.class.name }.join("\n ")}"
102
+ assert(false, message)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -64,7 +64,7 @@ module ActiveSupport
64
64
  module Subprocess
65
65
  ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
66
66
 
67
- # Complicated H4X to get this working in windows / jruby with
67
+ # Complicated H4X to get this working in Windows / JRuby with
68
68
  # no forking.
69
69
  def run_in_isolation(&blk)
70
70
  require "tempfile"