activesupport 7.0.7.2 → 7.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +742 -285
  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/builder.rb +1 -1
  10. data/lib/active_support/cache/coder.rb +153 -0
  11. data/lib/active_support/cache/entry.rb +128 -0
  12. data/lib/active_support/cache/file_store.rb +36 -9
  13. data/lib/active_support/cache/mem_cache_store.rb +84 -68
  14. data/lib/active_support/cache/memory_store.rb +76 -24
  15. data/lib/active_support/cache/null_store.rb +6 -0
  16. data/lib/active_support/cache/redis_cache_store.rb +128 -131
  17. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +20 -8
  19. data/lib/active_support/cache.rb +304 -246
  20. data/lib/active_support/callbacks.rb +38 -18
  21. data/lib/active_support/concern.rb +4 -2
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  23. data/lib/active_support/concurrency/null_lock.rb +13 -0
  24. data/lib/active_support/configurable.rb +10 -0
  25. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  26. data/lib/active_support/core_ext/array.rb +0 -1
  27. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  28. data/lib/active_support/core_ext/date/conversions.rb +1 -0
  29. data/lib/active_support/core_ext/date.rb +0 -1
  30. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  31. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  32. data/lib/active_support/core_ext/date_time.rb +0 -1
  33. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  34. data/lib/active_support/core_ext/enumerable.rb +3 -75
  35. data/lib/active_support/core_ext/erb/util.rb +196 -0
  36. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  37. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  38. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  39. data/lib/active_support/core_ext/module/delegation.rb +40 -11
  40. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  41. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  42. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  43. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  44. data/lib/active_support/core_ext/numeric.rb +0 -1
  45. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  46. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  47. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  48. data/lib/active_support/core_ext/object/json.rb +10 -2
  49. data/lib/active_support/core_ext/object/with.rb +44 -0
  50. data/lib/active_support/core_ext/object/with_options.rb +3 -3
  51. data/lib/active_support/core_ext/object.rb +1 -0
  52. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  53. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  54. data/lib/active_support/core_ext/pathname.rb +1 -0
  55. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  56. data/lib/active_support/core_ext/range/{overlaps.rb → overlap.rb} +5 -3
  57. data/lib/active_support/core_ext/range.rb +1 -2
  58. data/lib/active_support/core_ext/securerandom.rb +24 -12
  59. data/lib/active_support/core_ext/string/filters.rb +20 -14
  60. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  61. data/lib/active_support/core_ext/string/output_safety.rb +38 -174
  62. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  63. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  64. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  65. data/lib/active_support/core_ext/time/zones.rb +4 -4
  66. data/lib/active_support/core_ext/time.rb +0 -1
  67. data/lib/active_support/current_attributes.rb +15 -6
  68. data/lib/active_support/dependencies/autoload.rb +17 -12
  69. data/lib/active_support/deprecation/behaviors.rb +53 -32
  70. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  71. data/lib/active_support/deprecation/deprecators.rb +104 -0
  72. data/lib/active_support/deprecation/disallowed.rb +3 -5
  73. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  74. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  75. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  76. data/lib/active_support/deprecation/reporting.rb +35 -21
  77. data/lib/active_support/deprecation.rb +32 -5
  78. data/lib/active_support/deprecator.rb +7 -0
  79. data/lib/active_support/descendants_tracker.rb +104 -132
  80. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  81. data/lib/active_support/duration.rb +2 -1
  82. data/lib/active_support/encrypted_configuration.rb +30 -9
  83. data/lib/active_support/encrypted_file.rb +8 -3
  84. data/lib/active_support/environment_inquirer.rb +22 -2
  85. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  86. data/lib/active_support/error_reporter.rb +121 -35
  87. data/lib/active_support/execution_wrapper.rb +4 -4
  88. data/lib/active_support/file_update_checker.rb +4 -2
  89. data/lib/active_support/fork_tracker.rb +10 -2
  90. data/lib/active_support/gem_version.rb +4 -4
  91. data/lib/active_support/gzip.rb +2 -0
  92. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  93. data/lib/active_support/i18n.rb +1 -1
  94. data/lib/active_support/i18n_railtie.rb +20 -13
  95. data/lib/active_support/inflector/inflections.rb +2 -0
  96. data/lib/active_support/inflector/methods.rb +22 -10
  97. data/lib/active_support/inflector/transliterate.rb +3 -1
  98. data/lib/active_support/isolated_execution_state.rb +26 -22
  99. data/lib/active_support/json/decoding.rb +2 -1
  100. data/lib/active_support/json/encoding.rb +25 -43
  101. data/lib/active_support/key_generator.rb +9 -1
  102. data/lib/active_support/lazy_load_hooks.rb +6 -4
  103. data/lib/active_support/locale/en.yml +2 -0
  104. data/lib/active_support/log_subscriber.rb +78 -33
  105. data/lib/active_support/logger.rb +1 -1
  106. data/lib/active_support/logger_thread_safe_level.rb +9 -21
  107. data/lib/active_support/message_encryptor.rb +197 -53
  108. data/lib/active_support/message_encryptors.rb +140 -0
  109. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  110. data/lib/active_support/message_pack/extensions.rb +292 -0
  111. data/lib/active_support/message_pack/serializer.rb +63 -0
  112. data/lib/active_support/message_pack.rb +50 -0
  113. data/lib/active_support/message_verifier.rb +212 -93
  114. data/lib/active_support/message_verifiers.rb +134 -0
  115. data/lib/active_support/messages/codec.rb +65 -0
  116. data/lib/active_support/messages/metadata.rb +111 -45
  117. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  118. data/lib/active_support/messages/rotator.rb +34 -32
  119. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  120. data/lib/active_support/multibyte/chars.rb +2 -0
  121. data/lib/active_support/multibyte/unicode.rb +9 -37
  122. data/lib/active_support/notifications/fanout.rb +239 -81
  123. data/lib/active_support/notifications/instrumenter.rb +71 -14
  124. data/lib/active_support/notifications.rb +1 -1
  125. data/lib/active_support/number_helper/number_converter.rb +2 -2
  126. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  127. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  128. data/lib/active_support/ordered_hash.rb +3 -3
  129. data/lib/active_support/ordered_options.rb +14 -0
  130. data/lib/active_support/parameter_filter.rb +84 -69
  131. data/lib/active_support/proxy_object.rb +2 -0
  132. data/lib/active_support/railtie.rb +33 -21
  133. data/lib/active_support/reloader.rb +12 -4
  134. data/lib/active_support/rescuable.rb +2 -0
  135. data/lib/active_support/secure_compare_rotator.rb +16 -9
  136. data/lib/active_support/string_inquirer.rb +3 -1
  137. data/lib/active_support/subscriber.rb +9 -27
  138. data/lib/active_support/syntax_error_proxy.rb +49 -0
  139. data/lib/active_support/tagged_logging.rb +60 -24
  140. data/lib/active_support/test_case.rb +153 -6
  141. data/lib/active_support/testing/assertions.rb +25 -9
  142. data/lib/active_support/testing/autorun.rb +0 -2
  143. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  144. data/lib/active_support/testing/deprecation.rb +25 -25
  145. data/lib/active_support/testing/error_reporter_assertions.rb +108 -0
  146. data/lib/active_support/testing/isolation.rb +1 -1
  147. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  148. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  149. data/lib/active_support/testing/stream.rb +1 -1
  150. data/lib/active_support/testing/strict_warnings.rb +38 -0
  151. data/lib/active_support/testing/time_helpers.rb +32 -14
  152. data/lib/active_support/time_with_zone.rb +6 -42
  153. data/lib/active_support/values/time_zone.rb +9 -7
  154. data/lib/active_support/version.rb +1 -1
  155. data/lib/active_support/xml_mini/jdom.rb +3 -10
  156. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  157. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  158. data/lib/active_support/xml_mini/rexml.rb +1 -1
  159. data/lib/active_support/xml_mini.rb +2 -2
  160. data/lib/active_support.rb +13 -3
  161. metadata +103 -18
  162. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  163. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -37
  164. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -33
  165. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  166. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -33
  167. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  168. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -33
  169. data/lib/active_support/core_ext/uri.rb +0 -5
  170. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -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,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module ErrorReporterAssertions
6
+ module ErrorCollector
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
+ private
55
+ # Assertion that the block should not cause an exception to be reported
56
+ # to +Rails.error+.
57
+ #
58
+ # Passes if evaluated code in the yielded block reports no exception.
59
+ #
60
+ # assert_no_error_reported do
61
+ # perform_service(param: 'no_exception')
62
+ # end
63
+ def assert_no_error_reported(&block)
64
+ reports = ErrorCollector.record do
65
+ _assert_nothing_raised_or_warn("assert_no_error_reported", &block)
66
+ end
67
+ assert_predicate(reports, :empty?)
68
+ end
69
+
70
+ # Assertion that the block should cause at least one exception to be reported
71
+ # to +Rails.error+.
72
+ #
73
+ # Passes if the evaluated code in the yielded block reports a matching exception.
74
+ #
75
+ # assert_error_reported(IOError) do
76
+ # Rails.error.report(IOError.new("Oops"))
77
+ # end
78
+ #
79
+ # To test further details about the reported exception, you can use the return
80
+ # value.
81
+ #
82
+ # report = assert_error_reported(IOError) do
83
+ # # ...
84
+ # end
85
+ # assert_equal "Oops", report.error.message
86
+ # assert_equal "admin", report.context[:section]
87
+ # assert_equal :warning, report.severity
88
+ # assert_predicate report, :handled?
89
+ def assert_error_reported(error_class = StandardError, &block)
90
+ reports = ErrorCollector.record do
91
+ _assert_nothing_raised_or_warn("assert_error_reported", &block)
92
+ end
93
+
94
+ if reports.empty?
95
+ assert(false, "Expected a #{error_class.name} to be reported, but there were no errors reported.")
96
+ elsif (report = reports.find { |r| error_class === r.error })
97
+ self.assertions += 1
98
+ report
99
+ else
100
+ message = "Expected a #{error_class.name} to be reported, but none of the " \
101
+ "#{reports.size} reported errors matched: \n" \
102
+ "#{reports.map { |r| r.error.class.name }.join("\n ")}"
103
+ assert(false, message)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ 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"
@@ -17,24 +17,37 @@ module ActiveSupport
17
17
  assert_equal times, times_called, error
18
18
  end
19
19
 
20
- def assert_called_with(object, method_name, args, returns: nil, &block)
20
+ def assert_called_with(object, method_name, args, returns: false, **kwargs, &block)
21
21
  mock = Minitest::Mock.new
22
-
23
- if args.all?(Array)
24
- args.each { |arg| mock.expect(:call, returns, arg) }
25
- else
26
- mock.expect(:call, returns, args)
27
- end
22
+ expect_called_with(mock, args, returns: returns, **kwargs)
28
23
 
29
24
  object.stub(method_name, mock, &block)
30
25
 
31
- mock.verify
26
+ assert_mock(mock)
32
27
  end
33
28
 
34
29
  def assert_not_called(object, method_name, message = nil, &block)
35
30
  assert_called(object, method_name, message, times: 0, &block)
36
31
  end
37
32
 
33
+ #--
34
+ # This method is a temporary wrapper for mock.expect as part of
35
+ # the Minitest 5.16 / Ruby 3.0 kwargs transition. It can go away
36
+ # when we drop support for Ruby 2.7.
37
+ if Minitest::Mock.instance_method(:expect).parameters.map(&:first).include?(:keyrest)
38
+ def expect_called_with(mock, args, returns: false, **kwargs)
39
+ mock.expect(:call, returns, args, **kwargs)
40
+ end
41
+ else
42
+ def expect_called_with(mock, args, returns: false, **kwargs)
43
+ if !kwargs.empty?
44
+ mock.expect(:call, returns, [*args, kwargs])
45
+ else
46
+ mock.expect(:call, returns, args)
47
+ end
48
+ end
49
+ end
50
+
38
51
  def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
39
52
  times_called = 0
40
53
  klass.define_method("stubbed_#{method_name}") do |*|
@@ -9,6 +9,7 @@ module ActiveSupport
9
9
  @size = size
10
10
  @parallelize_with = with
11
11
  @threshold = threshold
12
+ @parallelized = false
12
13
  end
13
14
 
14
15
  def start
@@ -49,11 +50,15 @@ module ActiveSupport
49
50
  end
50
51
 
51
52
  def parallelized?
52
- @parallelized if defined?(@parallelized)
53
+ @parallelized
53
54
  end
54
55
 
55
56
  def should_parallelize?
56
- ENV["PARALLEL_WORKERS"] || tests_count > threshold
57
+ (ENV["PARALLEL_WORKERS"] || tests_count > threshold) && many_workers?
58
+ end
59
+
60
+ def many_workers?
61
+ size > 1
57
62
  end
58
63
 
59
64
  def tests_count
@@ -67,7 +72,7 @@ module ActiveSupport
67
72
  def execution_info
68
73
  if parallelized?
69
74
  "Running #{tests_count} tests in parallel using #{parallel_executor.size} #{parallelize_with}"
70
- else
75
+ elsif many_workers?
71
76
  "Running #{tests_count} tests in a single process (parallelization threshold is #{threshold})"
72
77
  end
73
78
  end
@@ -23,7 +23,7 @@ module ActiveSupport
23
23
  def capture(stream)
24
24
  stream = stream.to_s
25
25
  captured_stream = Tempfile.new(stream)
26
- stream_io = eval("$#{stream}")
26
+ stream_io = eval("$#{stream}", binding, __FILE__, __LINE__)
27
27
  origin_stream = stream_io.dup
28
28
  stream_io.reopen(captured_stream)
29
29
 
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ $VERBOSE = true
4
+ Warning[:deprecated] = true
5
+
6
+ module ActiveSupport
7
+ module RaiseWarnings # :nodoc:
8
+ PROJECT_ROOT = File.expand_path("../../../../", __dir__)
9
+ ALLOWED_WARNINGS = Regexp.union(
10
+ /circular require considered harmful.*delayed_job/, # Bug in delayed job.
11
+
12
+ # Expected non-verbose warning emitted by Rails.
13
+ /Ignoring .*\.yml because it has expired/,
14
+ /Failed to validate the schema cache because/,
15
+ )
16
+
17
+ SUPPRESSED_WARNINGS = Regexp.union(
18
+ # TODO: remove if https://github.com/mikel/mail/pull/1557 or similar fix
19
+ %r{/lib/mail/parsers/.*statement not reached},
20
+ %r{/lib/mail/parsers/.*assigned but unused variable - testEof}
21
+ )
22
+
23
+ def warn(message, *)
24
+ return if SUPPRESSED_WARNINGS.match?(message)
25
+
26
+ super
27
+
28
+ return unless message.include?(PROJECT_ROOT)
29
+ return if ALLOWED_WARNINGS.match?(message)
30
+ return unless ENV["RAILS_STRICT_WARNINGS"] || ENV["CI"]
31
+
32
+ raise message
33
+ end
34
+ ruby2_keywords :warn if respond_to?(:ruby2_keywords, true)
35
+ end
36
+ end
37
+
38
+ Warning.singleton_class.prepend(ActiveSupport::RaiseWarnings)