activesupport 6.1.6.1 → 7.0.3.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +231 -515
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +15 -9
- data/lib/active_support/cache/mem_cache_store.rb +132 -37
- data/lib/active_support/cache/memory_store.rb +24 -16
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +47 -72
- data/lib/active_support/cache/strategy/local_cache.rb +38 -61
- data/lib/active_support/cache.rb +193 -46
- data/lib/active_support/callbacks.rb +184 -85
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +5 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +8 -5
- data/lib/active_support/configuration_file.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +25 -17
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +14 -14
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -14
- data/lib/active_support/core_ext/enumerable.rb +101 -32
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +0 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +30 -25
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +62 -38
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +7 -8
- data/lib/active_support/core_ext/time/conversions.rb +13 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -27
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/current_attributes.rb +31 -14
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +5 -2
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation.rb +2 -2
- data/lib/active_support/descendants_tracker.rb +174 -68
- data/lib/active_support/digest.rb +4 -4
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -1
- data/lib/active_support/duration.rb +77 -48
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +3 -5
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +30 -11
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +19 -12
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +1 -1
- data/lib/active_support/inflector/inflections.rb +23 -7
- data/lib/active_support/inflector/methods.rb +24 -48
- data/lib/active_support/inflector/transliterate.rb +1 -1
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +22 -5
- data/lib/active_support/lazy_load_hooks.rb +14 -3
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +15 -5
- data/lib/active_support/logger.rb +4 -5
- data/lib/active_support/logger_thread_safe_level.rb +4 -13
- data/lib/active_support/message_encryptor.rb +12 -6
- data/lib/active_support/message_verifier.rb +46 -14
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte/unicode.rb +0 -12
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +91 -65
- data/lib/active_support/notifications/instrumenter.rb +32 -15
- data/lib/active_support/notifications.rb +17 -23
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/rounding_helper.rb +1 -5
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +8 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +5 -0
- data/lib/active_support/per_thread_registry.rb +5 -1
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +2 -2
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +7 -18
- data/lib/active_support/tagged_logging.rb +16 -1
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +35 -5
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +13 -2
- data/lib/active_support/time_with_zone.rb +58 -17
- data/lib/active_support/values/time_zone.rb +33 -14
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +16 -0
- metadata +23 -21
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -12,6 +12,7 @@ require "active_support/testing/constant_lookup"
|
|
12
12
|
require "active_support/testing/time_helpers"
|
13
13
|
require "active_support/testing/file_fixtures"
|
14
14
|
require "active_support/testing/parallelization"
|
15
|
+
require "active_support/testing/parallelize_executor"
|
15
16
|
require "concurrent/utility/processor_counter"
|
16
17
|
|
17
18
|
module ActiveSupport
|
@@ -71,26 +72,17 @@ module ActiveSupport
|
|
71
72
|
#
|
72
73
|
# The threaded parallelization uses minitest's parallel executor directly.
|
73
74
|
# The processes parallelization uses a Ruby DRb server.
|
74
|
-
|
75
|
+
#
|
76
|
+
# Because parallelization presents an overhead, it is only enabled when the
|
77
|
+
# number of tests to run is above the +threshold+ param. The default value is
|
78
|
+
# 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
|
79
|
+
def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
|
75
80
|
workers = Concurrent.physical_processor_count if workers == :number_of_processors
|
76
81
|
workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
|
77
82
|
|
78
83
|
return if workers <= 1
|
79
84
|
|
80
|
-
|
81
|
-
when :processes
|
82
|
-
Testing::Parallelization.new(workers)
|
83
|
-
when :threads
|
84
|
-
Minitest::Parallel::Executor.new(workers)
|
85
|
-
else
|
86
|
-
raise ArgumentError, "#{with} is not a supported parallelization executor."
|
87
|
-
end
|
88
|
-
|
89
|
-
self.lock_threads = false if defined?(self.lock_threads) && with == :threads
|
90
|
-
|
91
|
-
Minitest.parallel_executor = executor
|
92
|
-
|
93
|
-
parallelize_me!
|
85
|
+
Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
|
94
86
|
end
|
95
87
|
|
96
88
|
# Set up hook for parallel testing. This can be used if you have multiple
|
@@ -107,9 +99,7 @@ module ActiveSupport
|
|
107
99
|
# end
|
108
100
|
# end
|
109
101
|
def parallelize_setup(&block)
|
110
|
-
ActiveSupport::Testing::Parallelization.after_fork_hook
|
111
|
-
yield worker
|
112
|
-
end
|
102
|
+
ActiveSupport::Testing::Parallelization.after_fork_hook(&block)
|
113
103
|
end
|
114
104
|
|
115
105
|
# Clean up hook for parallel testing. This can be used to drop databases
|
@@ -126,9 +116,7 @@ module ActiveSupport
|
|
126
116
|
# end
|
127
117
|
# end
|
128
118
|
def parallelize_teardown(&block)
|
129
|
-
ActiveSupport::Testing::Parallelization.run_cleanup_hook
|
130
|
-
yield worker
|
131
|
-
end
|
119
|
+
ActiveSupport::Testing::Parallelization.run_cleanup_hook(&block)
|
132
120
|
end
|
133
121
|
end
|
134
122
|
|
@@ -99,7 +99,7 @@ module ActiveSupport
|
|
99
99
|
}
|
100
100
|
before = exps.map(&:call)
|
101
101
|
|
102
|
-
retval =
|
102
|
+
retval = _assert_nothing_raised_or_warn("assert_difference", &block)
|
103
103
|
|
104
104
|
expressions.zip(exps, before) do |(code, diff), exp, before_value|
|
105
105
|
error = "#{code.inspect} didn't change by #{diff}"
|
@@ -159,7 +159,7 @@ module ActiveSupport
|
|
159
159
|
# @object = 42
|
160
160
|
# end
|
161
161
|
#
|
162
|
-
# The keyword arguments
|
162
|
+
# The keyword arguments +:from+ and +:to+ can be given to specify the
|
163
163
|
# expected initial value and the expected value after the block was
|
164
164
|
# executed.
|
165
165
|
#
|
@@ -176,7 +176,7 @@ module ActiveSupport
|
|
176
176
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
177
177
|
|
178
178
|
before = exp.call
|
179
|
-
retval =
|
179
|
+
retval = _assert_nothing_raised_or_warn("assert_changes", &block)
|
180
180
|
|
181
181
|
unless from == UNTRACKED
|
182
182
|
error = "Expected change from #{from.inspect}"
|
@@ -207,16 +207,30 @@ module ActiveSupport
|
|
207
207
|
# post :create, params: { status: { ok: true } }
|
208
208
|
# end
|
209
209
|
#
|
210
|
+
# Provide the optional keyword argument :from to specify the expected
|
211
|
+
# initial value.
|
212
|
+
#
|
213
|
+
# assert_no_changes -> { Status.all_good? }, from: true do
|
214
|
+
# post :create, params: { status: { ok: true } }
|
215
|
+
# end
|
216
|
+
#
|
210
217
|
# An error message can be specified.
|
211
218
|
#
|
212
219
|
# assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
|
213
220
|
# post :create, params: { status: { ok: false } }
|
214
221
|
# end
|
215
|
-
def assert_no_changes(expression, message = nil, &block)
|
222
|
+
def assert_no_changes(expression, message = nil, from: UNTRACKED, &block)
|
216
223
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
217
224
|
|
218
225
|
before = exp.call
|
219
|
-
retval =
|
226
|
+
retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
|
227
|
+
|
228
|
+
unless from == UNTRACKED
|
229
|
+
error = "Expected initial value of #{from.inspect}"
|
230
|
+
error = "#{message}.\n#{error}" if message
|
231
|
+
assert from === before, error
|
232
|
+
end
|
233
|
+
|
220
234
|
after = exp.call
|
221
235
|
|
222
236
|
error = "#{expression.inspect} changed"
|
@@ -230,6 +244,22 @@ module ActiveSupport
|
|
230
244
|
|
231
245
|
retval
|
232
246
|
end
|
247
|
+
|
248
|
+
private
|
249
|
+
def _assert_nothing_raised_or_warn(assertion, &block)
|
250
|
+
assert_nothing_raised(&block)
|
251
|
+
rescue Minitest::UnexpectedError => e
|
252
|
+
if tagged_logger && tagged_logger.warn?
|
253
|
+
warning = <<~MSG
|
254
|
+
#{self.class} - #{name}: #{e.error.class} raised.
|
255
|
+
If you expected this exception, use `assert_raises` as near to the code that raises as possible.
|
256
|
+
Other block based assertions (e.g. `#{assertion}`) can be used, as long as `assert_raises` is inside their block.
|
257
|
+
MSG
|
258
|
+
tagged_logger.warn warning
|
259
|
+
end
|
260
|
+
|
261
|
+
raise
|
262
|
+
end
|
233
263
|
end
|
234
264
|
end
|
235
265
|
end
|
@@ -4,7 +4,30 @@ require "active_support/deprecation"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module Testing
|
7
|
-
module Deprecation
|
7
|
+
module Deprecation
|
8
|
+
# Asserts that a matching deprecation warning was emitted by the given deprecator during the execution of the yielded block.
|
9
|
+
#
|
10
|
+
# assert_deprecated(/foo/, CustomDeprecator) do
|
11
|
+
# CustomDeprecator.warn "foo should no longer be used"
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# The +match+ object may be a +Regexp+, or +String+ appearing in the message.
|
15
|
+
#
|
16
|
+
# assert_deprecated('foo', CustomDeprecator) do
|
17
|
+
# CustomDeprecator.warn "foo should no longer be used"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# If the +match+ is omitted (or explicitly +nil+), any deprecation warning will match.
|
21
|
+
#
|
22
|
+
# assert_deprecated(nil, CustomDeprecator) do
|
23
|
+
# CustomDeprecator.warn "foo should no longer be used"
|
24
|
+
# 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
|
8
31
|
def assert_deprecated(match = nil, deprecator = nil, &block)
|
9
32
|
result, warnings = collect_deprecations(deprecator, &block)
|
10
33
|
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
|
@@ -15,12 +38,40 @@ module ActiveSupport
|
|
15
38
|
result
|
16
39
|
end
|
17
40
|
|
41
|
+
# Asserts that no deprecation warnings are emitted by the given deprecator during the execution of the yielded block.
|
42
|
+
#
|
43
|
+
# assert_not_deprecated(CustomDeprecator) do
|
44
|
+
# CustomDeprecator.warn "message" # fails assertion
|
45
|
+
# end
|
46
|
+
#
|
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
|
55
|
+
# end
|
18
56
|
def assert_not_deprecated(deprecator = nil, &block)
|
19
57
|
result, deprecations = collect_deprecations(deprecator, &block)
|
20
58
|
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
|
21
59
|
result
|
22
60
|
end
|
23
61
|
|
62
|
+
# Returns an array of all the deprecation warnings emitted by the given
|
63
|
+
# +deprecator+ during the execution of the yielded block.
|
64
|
+
#
|
65
|
+
# collect_deprecations(CustomDeprecator) do
|
66
|
+
# 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"]
|
24
75
|
def collect_deprecations(deprecator = nil)
|
25
76
|
deprecator ||= ActiveSupport::Deprecation
|
26
77
|
old_behavior = deprecator.behavior
|
@@ -5,7 +5,7 @@ module ActiveSupport
|
|
5
5
|
module Isolation
|
6
6
|
require "thread"
|
7
7
|
|
8
|
-
def self.included(klass)
|
8
|
+
def self.included(klass) # :nodoc:
|
9
9
|
klass.class_eval do
|
10
10
|
parallelize_me!
|
11
11
|
end
|
@@ -63,7 +63,7 @@ module ActiveSupport
|
|
63
63
|
module Subprocess
|
64
64
|
ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
|
65
65
|
|
66
|
-
#
|
66
|
+
# Complicated H4X to get this working in windows / jruby with
|
67
67
|
# no forking.
|
68
68
|
def run_in_isolation(&blk)
|
69
69
|
require "tempfile"
|
@@ -6,10 +6,10 @@ module ActiveSupport
|
|
6
6
|
module Testing
|
7
7
|
module MethodCallAssertions # :nodoc:
|
8
8
|
private
|
9
|
-
def assert_called(object, method_name, message = nil, times: 1, returns: nil)
|
9
|
+
def assert_called(object, method_name, message = nil, times: 1, returns: nil, &block)
|
10
10
|
times_called = 0
|
11
11
|
|
12
|
-
object.stub(method_name, proc { times_called += 1; returns })
|
12
|
+
object.stub(method_name, proc { times_called += 1; returns }, &block)
|
13
13
|
|
14
14
|
error = "Expected #{method_name} to be called #{times} times, " \
|
15
15
|
"but was called #{times_called} times"
|
@@ -17,16 +17,16 @@ 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)
|
20
|
+
def assert_called_with(object, method_name, args, returns: nil, &block)
|
21
21
|
mock = Minitest::Mock.new
|
22
22
|
|
23
|
-
if args.all?
|
23
|
+
if args.all?(Array)
|
24
24
|
args.each { |arg| mock.expect(:call, returns, arg) }
|
25
25
|
else
|
26
26
|
mock.expect(:call, returns, args)
|
27
27
|
end
|
28
28
|
|
29
|
-
object.stub(method_name, mock)
|
29
|
+
object.stub(method_name, mock, &block)
|
30
30
|
|
31
31
|
mock.verify
|
32
32
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Testing
|
5
|
+
class ParallelizeExecutor # :nodoc:
|
6
|
+
attr_reader :size, :parallelize_with, :threshold
|
7
|
+
|
8
|
+
def initialize(size:, with:, threshold: ActiveSupport.test_parallelization_threshold)
|
9
|
+
@size = size
|
10
|
+
@parallelize_with = with
|
11
|
+
@threshold = threshold
|
12
|
+
end
|
13
|
+
|
14
|
+
def start
|
15
|
+
parallelize if should_parallelize?
|
16
|
+
show_execution_info
|
17
|
+
|
18
|
+
parallel_executor.start if parallelized?
|
19
|
+
end
|
20
|
+
|
21
|
+
def <<(work)
|
22
|
+
parallel_executor << work if parallelized?
|
23
|
+
end
|
24
|
+
|
25
|
+
def shutdown
|
26
|
+
parallel_executor.shutdown if parallelized?
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def parallel_executor
|
31
|
+
@parallel_executor ||= build_parallel_executor
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_parallel_executor
|
35
|
+
case parallelize_with
|
36
|
+
when :processes
|
37
|
+
Testing::Parallelization.new(size)
|
38
|
+
when :threads
|
39
|
+
ActiveSupport::TestCase.lock_threads = false if defined?(ActiveSupport::TestCase.lock_threads)
|
40
|
+
Minitest::Parallel::Executor.new(size)
|
41
|
+
else
|
42
|
+
raise ArgumentError, "#{parallelize_with} is not a supported parallelization executor."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def parallelize
|
47
|
+
@parallelized = true
|
48
|
+
Minitest::Test.parallelize_me!
|
49
|
+
end
|
50
|
+
|
51
|
+
def parallelized?
|
52
|
+
@parallelized if defined?(@parallelized)
|
53
|
+
end
|
54
|
+
|
55
|
+
def should_parallelize?
|
56
|
+
ENV["PARALLEL_WORKERS"] || tests_count > threshold
|
57
|
+
end
|
58
|
+
|
59
|
+
def tests_count
|
60
|
+
@tests_count ||= Minitest::Runnable.runnables.sum { |runnable| runnable.runnable_methods.size }
|
61
|
+
end
|
62
|
+
|
63
|
+
def show_execution_info
|
64
|
+
puts execution_info
|
65
|
+
end
|
66
|
+
|
67
|
+
def execution_info
|
68
|
+
if parallelized?
|
69
|
+
"Running #{tests_count} tests in parallel using #{parallel_executor.size} #{parallelize_with}"
|
70
|
+
else
|
71
|
+
"Running #{tests_count} tests in a single process (parallelization threshold is #{threshold})"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
4
|
module Testing
|
5
|
-
module Stream
|
5
|
+
module Stream # :nodoc:
|
6
6
|
private
|
7
7
|
def silence_stream(stream)
|
8
8
|
old_stream = stream.dup
|
@@ -14,11 +14,9 @@ module ActiveSupport
|
|
14
14
|
old_stream.close
|
15
15
|
end
|
16
16
|
|
17
|
-
def quietly
|
17
|
+
def quietly(&block)
|
18
18
|
silence_stream(STDOUT) do
|
19
|
-
silence_stream(STDERR)
|
20
|
-
yield
|
21
|
-
end
|
19
|
+
silence_stream(STDERR, &block)
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
@@ -4,7 +4,7 @@ module ActiveSupport
|
|
4
4
|
module Testing
|
5
5
|
# Logs a "PostsControllerTest: test name" heading before each test to
|
6
6
|
# make test.log easier to search and follow along with.
|
7
|
-
module TaggedLogging
|
7
|
+
module TaggedLogging # :nodoc:
|
8
8
|
attr_writer :tagged_logger
|
9
9
|
|
10
10
|
def before_setup
|
@@ -126,7 +126,7 @@ module ActiveSupport
|
|
126
126
|
# end
|
127
127
|
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
128
128
|
def travel_to(date_or_time)
|
129
|
-
if block_given? &&
|
129
|
+
if block_given? && in_block
|
130
130
|
travel_to_nested_block_call = <<~MSG
|
131
131
|
|
132
132
|
Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
|
@@ -156,19 +156,28 @@ module ActiveSupport
|
|
156
156
|
|
157
157
|
if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
|
158
158
|
now = date_or_time.midnight.to_time
|
159
|
+
elsif date_or_time.is_a?(String)
|
160
|
+
now = Time.zone.parse(date_or_time)
|
159
161
|
else
|
160
162
|
now = date_or_time.to_time.change(usec: 0)
|
161
163
|
end
|
162
164
|
|
165
|
+
stubbed_time = Time.now if simple_stubs.stubbing(Time, :now)
|
163
166
|
simple_stubs.stub_object(Time, :now) { at(now.to_i) }
|
164
167
|
simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
|
165
168
|
simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
|
166
169
|
|
167
170
|
if block_given?
|
168
171
|
begin
|
172
|
+
self.in_block = true
|
169
173
|
yield
|
170
174
|
ensure
|
171
|
-
|
175
|
+
if stubbed_time
|
176
|
+
travel_to stubbed_time
|
177
|
+
else
|
178
|
+
travel_back
|
179
|
+
end
|
180
|
+
self.in_block = false
|
172
181
|
end
|
173
182
|
end
|
174
183
|
end
|
@@ -230,6 +239,8 @@ module ActiveSupport
|
|
230
239
|
def simple_stubs
|
231
240
|
@simple_stubs ||= SimpleStubs.new
|
232
241
|
end
|
242
|
+
|
243
|
+
attr_accessor :in_block
|
233
244
|
end
|
234
245
|
end
|
235
246
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "yaml"
|
4
|
+
|
3
5
|
require "active_support/duration"
|
4
6
|
require "active_support/values/time_zone"
|
5
7
|
require "active_support/core_ext/object/acts_like"
|
@@ -11,7 +13,7 @@ module ActiveSupport
|
|
11
13
|
# system's <tt>ENV['TZ']</tt> zone.
|
12
14
|
#
|
13
15
|
# You shouldn't ever need to create a TimeWithZone instance directly via +new+.
|
14
|
-
# Instead use methods +local+, +parse+, +at
|
16
|
+
# Instead use methods +local+, +parse+, +at+, and +now+ on TimeZone instances,
|
15
17
|
# and +in_time_zone+ on Time and DateTime instances.
|
16
18
|
#
|
17
19
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
@@ -31,7 +33,7 @@ module ActiveSupport
|
|
31
33
|
# t.dst? # => true
|
32
34
|
# t.utc_offset # => -14400
|
33
35
|
# t.zone # => "EDT"
|
34
|
-
# t.
|
36
|
+
# t.to_fs(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
|
35
37
|
# t + 1.day # => Mon, 19 May 2008 13:27:25.031505668 EDT -04:00
|
36
38
|
# t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00.000000000 EST -05:00
|
37
39
|
# t > Time.utc(1999) # => true
|
@@ -40,6 +42,13 @@ module ActiveSupport
|
|
40
42
|
class TimeWithZone
|
41
43
|
# Report class name as 'Time' to thwart type checking.
|
42
44
|
def self.name
|
45
|
+
ActiveSupport::Deprecation.warn(<<~EOM)
|
46
|
+
ActiveSupport::TimeWithZone.name has been deprecated and
|
47
|
+
from Rails 7.1 will use the default Ruby implementation.
|
48
|
+
You can set `config.active_support.remove_deprecated_time_with_zone_name = true`
|
49
|
+
to enable the new behavior now.
|
50
|
+
EOM
|
51
|
+
|
43
52
|
"Time"
|
44
53
|
end
|
45
54
|
|
@@ -69,7 +78,7 @@ module ActiveSupport
|
|
69
78
|
alias_method :getutc, :utc
|
70
79
|
alias_method :gmtime, :utc
|
71
80
|
|
72
|
-
# Returns the underlying TZInfo::TimezonePeriod
|
81
|
+
# Returns the underlying <tt>TZInfo::TimezonePeriod</tt>.
|
73
82
|
def period
|
74
83
|
@period ||= time_zone.period_for_utc(@utc)
|
75
84
|
end
|
@@ -172,12 +181,11 @@ module ActiveSupport
|
|
172
181
|
end
|
173
182
|
end
|
174
183
|
|
175
|
-
def init_with(coder)
|
184
|
+
def init_with(coder) # :nodoc:
|
176
185
|
initialize(coder["utc"], coder["zone"], coder["time"])
|
177
186
|
end
|
178
187
|
|
179
|
-
def encode_with(coder)
|
180
|
-
coder.tag = "!ruby/object:ActiveSupport::TimeWithZone"
|
188
|
+
def encode_with(coder) # :nodoc:
|
181
189
|
coder.map = { "utc" => utc, "zone" => time_zone, "time" => time }
|
182
190
|
end
|
183
191
|
|
@@ -194,25 +202,53 @@ module ActiveSupport
|
|
194
202
|
#
|
195
203
|
# Time.zone.now.rfc2822 # => "Tue, 01 Jan 2013 04:51:39 +0000"
|
196
204
|
def rfc2822
|
197
|
-
|
205
|
+
to_fs(:rfc822)
|
198
206
|
end
|
199
207
|
alias_method :rfc822, :rfc2822
|
200
208
|
|
209
|
+
NOT_SET = Object.new # :nodoc:
|
210
|
+
|
201
211
|
# Returns a string of the object's date and time.
|
212
|
+
def to_s(format = NOT_SET)
|
213
|
+
if format == :db
|
214
|
+
ActiveSupport::Deprecation.warn(
|
215
|
+
"TimeWithZone#to_s(:db) is deprecated. Please use TimeWithZone#to_fs(:db) instead."
|
216
|
+
)
|
217
|
+
utc.to_fs(format)
|
218
|
+
elsif formatter = ::Time::DATE_FORMATS[format]
|
219
|
+
ActiveSupport::Deprecation.warn(
|
220
|
+
"TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
|
221
|
+
)
|
222
|
+
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
223
|
+
elsif format == NOT_SET
|
224
|
+
"#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
|
225
|
+
else
|
226
|
+
ActiveSupport::Deprecation.warn(
|
227
|
+
"TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
|
228
|
+
)
|
229
|
+
"#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Returns a string of the object's date and time.
|
234
|
+
#
|
235
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
236
|
+
#
|
202
237
|
# Accepts an optional <tt>format</tt>:
|
203
238
|
# * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
|
204
|
-
# * <tt>:db</tt> - format outputs time in UTC :db time. See Time#
|
239
|
+
# * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_fs(:db).
|
205
240
|
# * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
|
206
|
-
def
|
241
|
+
def to_fs(format = :default)
|
207
242
|
if format == :db
|
208
|
-
utc.
|
243
|
+
utc.to_fs(format)
|
209
244
|
elsif formatter = ::Time::DATE_FORMATS[format]
|
210
245
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
211
246
|
else
|
212
|
-
|
247
|
+
# Change to to_s when deprecation is gone.
|
248
|
+
"#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}"
|
213
249
|
end
|
214
250
|
end
|
215
|
-
alias_method :to_formatted_s, :
|
251
|
+
alias_method :to_formatted_s, :to_fs
|
216
252
|
|
217
253
|
# Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
|
218
254
|
# so that zone information is correct.
|
@@ -359,8 +395,8 @@ module ActiveSupport
|
|
359
395
|
# Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
|
360
396
|
# been changed according to the +options+ parameter. The time options (<tt>:hour</tt>,
|
361
397
|
# <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly,
|
362
|
-
# so if only the hour is passed, then minute, sec, usec and nsec is set to 0. If the
|
363
|
-
# hour and minute is passed, then sec, usec and nsec is set to 0. The +options+
|
398
|
+
# so if only the hour is passed, then minute, sec, usec, and nsec is set to 0. If the
|
399
|
+
# hour and minute is passed, then sec, usec, and nsec is set to 0. The +options+
|
364
400
|
# parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
|
365
401
|
# <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>,
|
366
402
|
# <tt>:nsec</tt>, <tt>:offset</tt>, <tt>:zone</tt>. Pass either <tt>:usec</tt>
|
@@ -440,7 +476,7 @@ module ActiveSupport
|
|
440
476
|
[time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
|
441
477
|
end
|
442
478
|
|
443
|
-
# Returns the object's date and time as a floating
|
479
|
+
# Returns the object's date and time as a floating-point number of seconds
|
444
480
|
# since the Epoch (January 1, 1970 00:00 UTC).
|
445
481
|
#
|
446
482
|
# Time.zone.now.to_f # => 1417709320.285418
|
@@ -534,7 +570,7 @@ module ActiveSupport
|
|
534
570
|
def method_missing(sym, *args, &block)
|
535
571
|
wrap_with_time_zone time.__send__(sym, *args, &block)
|
536
572
|
rescue NoMethodError => e
|
537
|
-
raise e, e.message.sub(time.inspect, inspect), e.backtrace
|
573
|
+
raise e, e.message.sub(time.inspect, inspect).sub("Time", "ActiveSupport::TimeWithZone"), e.backtrace
|
538
574
|
end
|
539
575
|
|
540
576
|
private
|
@@ -568,7 +604,7 @@ module ActiveSupport
|
|
568
604
|
end
|
569
605
|
|
570
606
|
def duration_of_variable_length?(obj)
|
571
|
-
ActiveSupport::Duration === obj && obj.
|
607
|
+
ActiveSupport::Duration === obj && obj.variable?
|
572
608
|
end
|
573
609
|
|
574
610
|
def wrap_with_time_zone(time)
|
@@ -583,3 +619,8 @@ module ActiveSupport
|
|
583
619
|
end
|
584
620
|
end
|
585
621
|
end
|
622
|
+
|
623
|
+
# These prevent Psych from calling `ActiveSupport::TimeWithZone.name`
|
624
|
+
# and triggering the deprecation warning about the change in Rails 7.1.
|
625
|
+
YAML.load_tags["!ruby/object:ActiveSupport::TimeWithZone"] = "ActiveSupport::TimeWithZone"
|
626
|
+
YAML.dump_tags[ActiveSupport::TimeWithZone] = "!ruby/object:ActiveSupport::TimeWithZone"
|