activesupport 7.0.8.7 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +143 -459
  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 +3 -1
  7. data/lib/active_support/backtrace_cleaner.rb +39 -7
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +251 -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 +134 -0
  13. data/lib/active_support/cache/file_store.rb +49 -17
  14. data/lib/active_support/cache/mem_cache_store.rb +94 -128
  15. data/lib/active_support/cache/memory_store.rb +80 -25
  16. data/lib/active_support/cache/null_store.rb +6 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +165 -152
  18. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +29 -14
  20. data/lib/active_support/cache.rb +363 -291
  21. data/lib/active_support/callbacks.rb +118 -134
  22. data/lib/active_support/code_generator.rb +15 -10
  23. data/lib/active_support/concern.rb +4 -2
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/configurable.rb +10 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +1 -2
  28. data/lib/active_support/core_ext/array.rb +0 -1
  29. data/lib/active_support/core_ext/class/subclasses.rb +17 -34
  30. data/lib/active_support/core_ext/date/blank.rb +4 -0
  31. data/lib/active_support/core_ext/date/conversions.rb +1 -2
  32. data/lib/active_support/core_ext/date.rb +0 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  35. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  36. data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
  37. data/lib/active_support/core_ext/date_time.rb +0 -1
  38. data/lib/active_support/core_ext/digest/uuid.rb +7 -10
  39. data/lib/active_support/core_ext/enumerable.rb +3 -75
  40. data/lib/active_support/core_ext/erb/util.rb +201 -0
  41. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  42. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  43. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  44. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  45. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  46. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  47. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  48. data/lib/active_support/core_ext/module/delegation.rb +20 -119
  49. data/lib/active_support/core_ext/module/deprecation.rb +12 -12
  50. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  51. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  52. data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
  53. data/lib/active_support/core_ext/numeric.rb +0 -1
  54. data/lib/active_support/core_ext/object/blank.rb +45 -1
  55. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  56. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  57. data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
  58. data/lib/active_support/core_ext/object/json.rb +17 -7
  59. data/lib/active_support/core_ext/object/with.rb +46 -0
  60. data/lib/active_support/core_ext/object/with_options.rb +4 -4
  61. data/lib/active_support/core_ext/object.rb +1 -0
  62. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  63. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  64. data/lib/active_support/core_ext/pathname.rb +1 -0
  65. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  66. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  67. data/lib/active_support/core_ext/range.rb +1 -2
  68. data/lib/active_support/core_ext/securerandom.rb +1 -5
  69. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  70. data/lib/active_support/core_ext/string/filters.rb +21 -15
  71. data/lib/active_support/core_ext/string/indent.rb +1 -1
  72. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  73. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  74. data/lib/active_support/core_ext/string/output_safety.rb +34 -177
  75. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  76. data/lib/active_support/core_ext/time/calculations.rb +36 -30
  77. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  78. data/lib/active_support/core_ext/time/conversions.rb +1 -3
  79. data/lib/active_support/core_ext/time/zones.rb +4 -4
  80. data/lib/active_support/core_ext/time.rb +0 -1
  81. data/lib/active_support/core_ext.rb +0 -1
  82. data/lib/active_support/current_attributes.rb +53 -46
  83. data/lib/active_support/deep_mergeable.rb +53 -0
  84. data/lib/active_support/delegation.rb +202 -0
  85. data/lib/active_support/dependencies/autoload.rb +9 -16
  86. data/lib/active_support/deprecation/behaviors.rb +65 -42
  87. data/lib/active_support/deprecation/constant_accessor.rb +47 -25
  88. data/lib/active_support/deprecation/deprecators.rb +104 -0
  89. data/lib/active_support/deprecation/disallowed.rb +3 -5
  90. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  91. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
  92. data/lib/active_support/deprecation/reporting.rb +49 -27
  93. data/lib/active_support/deprecation.rb +39 -9
  94. data/lib/active_support/deprecator.rb +7 -0
  95. data/lib/active_support/descendants_tracker.rb +66 -172
  96. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  97. data/lib/active_support/duration/iso8601_serializer.rb +1 -4
  98. data/lib/active_support/duration.rb +13 -7
  99. data/lib/active_support/encrypted_configuration.rb +30 -9
  100. data/lib/active_support/encrypted_file.rb +9 -4
  101. data/lib/active_support/environment_inquirer.rb +22 -2
  102. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  103. data/lib/active_support/error_reporter.rb +160 -36
  104. data/lib/active_support/evented_file_update_checker.rb +0 -1
  105. data/lib/active_support/execution_wrapper.rb +4 -5
  106. data/lib/active_support/file_update_checker.rb +5 -3
  107. data/lib/active_support/fork_tracker.rb +4 -32
  108. data/lib/active_support/gem_version.rb +4 -4
  109. data/lib/active_support/gzip.rb +2 -0
  110. data/lib/active_support/hash_with_indifferent_access.rb +41 -25
  111. data/lib/active_support/html_safe_translation.rb +19 -6
  112. data/lib/active_support/i18n.rb +1 -1
  113. data/lib/active_support/i18n_railtie.rb +20 -13
  114. data/lib/active_support/inflector/inflections.rb +2 -0
  115. data/lib/active_support/inflector/methods.rb +23 -11
  116. data/lib/active_support/inflector/transliterate.rb +3 -1
  117. data/lib/active_support/isolated_execution_state.rb +26 -22
  118. data/lib/active_support/json/decoding.rb +2 -1
  119. data/lib/active_support/json/encoding.rb +25 -43
  120. data/lib/active_support/key_generator.rb +9 -1
  121. data/lib/active_support/lazy_load_hooks.rb +6 -4
  122. data/lib/active_support/locale/en.yml +2 -0
  123. data/lib/active_support/log_subscriber.rb +74 -34
  124. data/lib/active_support/logger.rb +22 -60
  125. data/lib/active_support/logger_thread_safe_level.rb +10 -32
  126. data/lib/active_support/message_encryptor.rb +197 -53
  127. data/lib/active_support/message_encryptors.rb +141 -0
  128. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  129. data/lib/active_support/message_pack/extensions.rb +305 -0
  130. data/lib/active_support/message_pack/serializer.rb +63 -0
  131. data/lib/active_support/message_pack.rb +50 -0
  132. data/lib/active_support/message_verifier.rb +220 -89
  133. data/lib/active_support/message_verifiers.rb +135 -0
  134. data/lib/active_support/messages/codec.rb +65 -0
  135. data/lib/active_support/messages/metadata.rb +111 -45
  136. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  137. data/lib/active_support/messages/rotator.rb +34 -32
  138. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  139. data/lib/active_support/multibyte/chars.rb +4 -2
  140. data/lib/active_support/multibyte/unicode.rb +9 -37
  141. data/lib/active_support/notifications/fanout.rb +248 -87
  142. data/lib/active_support/notifications/instrumenter.rb +93 -25
  143. data/lib/active_support/notifications.rb +29 -28
  144. data/lib/active_support/number_helper/number_converter.rb +16 -7
  145. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  147. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  148. data/lib/active_support/number_helper.rb +379 -318
  149. data/lib/active_support/option_merger.rb +2 -2
  150. data/lib/active_support/ordered_hash.rb +3 -3
  151. data/lib/active_support/ordered_options.rb +67 -15
  152. data/lib/active_support/parameter_filter.rb +84 -69
  153. data/lib/active_support/proxy_object.rb +8 -3
  154. data/lib/active_support/railtie.rb +25 -20
  155. data/lib/active_support/reloader.rb +12 -4
  156. data/lib/active_support/rescuable.rb +2 -0
  157. data/lib/active_support/secure_compare_rotator.rb +16 -9
  158. data/lib/active_support/string_inquirer.rb +4 -2
  159. data/lib/active_support/subscriber.rb +10 -27
  160. data/lib/active_support/syntax_error_proxy.rb +60 -0
  161. data/lib/active_support/tagged_logging.rb +64 -25
  162. data/lib/active_support/test_case.rb +156 -7
  163. data/lib/active_support/testing/assertions.rb +28 -12
  164. data/lib/active_support/testing/autorun.rb +0 -2
  165. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  166. data/lib/active_support/testing/deprecation.rb +20 -27
  167. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  168. data/lib/active_support/testing/isolation.rb +21 -9
  169. data/lib/active_support/testing/method_call_assertions.rb +7 -8
  170. data/lib/active_support/testing/parallelization/server.rb +3 -0
  171. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  172. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  173. data/lib/active_support/testing/stream.rb +1 -1
  174. data/lib/active_support/testing/strict_warnings.rb +43 -0
  175. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  176. data/lib/active_support/testing/time_helpers.rb +38 -16
  177. data/lib/active_support/time_with_zone.rb +12 -18
  178. data/lib/active_support/values/time_zone.rb +25 -14
  179. data/lib/active_support/version.rb +1 -1
  180. data/lib/active_support/xml_mini/jdom.rb +3 -10
  181. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  182. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  183. data/lib/active_support/xml_mini/rexml.rb +1 -1
  184. data/lib/active_support/xml_mini.rb +12 -3
  185. data/lib/active_support.rb +15 -3
  186. metadata +140 -19
  187. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  188. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
  189. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
  190. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  191. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
  192. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  193. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  194. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
  195. data/lib/active_support/core_ext/uri.rb +0 -5
  196. data/lib/active_support/deprecation/instance_delegator.rb +0 -38
  197. data/lib/active_support/per_thread_registry.rb +0 -65
  198. data/lib/active_support/ruby_features.rb +0 -7
@@ -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
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/testing/parallelize_executor"
4
+
3
5
  module ActiveSupport
4
6
  module Testing
5
7
  module Isolation
6
8
  require "thread"
7
9
 
10
+ SubprocessCrashed = Class.new(StandardError)
11
+
8
12
  def self.included(klass) # :nodoc:
9
13
  klass.class_eval do
10
- parallelize_me!
14
+ parallelize_me! unless Minitest.parallel_executor.is_a?(ActiveSupport::Testing::ParallelizeExecutor)
11
15
  end
12
16
  end
13
17
 
@@ -16,10 +20,17 @@ module ActiveSupport
16
20
  end
17
21
 
18
22
  def run
19
- serialized = run_in_isolation do
23
+ status, serialized = run_in_isolation do
20
24
  super
21
25
  end
22
26
 
27
+ unless status&.success?
28
+ error = SubprocessCrashed.new("Subprocess exited with an error: #{status.inspect}\noutput: #{serialized.inspect}")
29
+ error.set_backtrace(caller)
30
+ self.failures << Minitest::UnexpectedError.new(error)
31
+ return defined?(Minitest::Result) ? Minitest::Result.from(self) : dup
32
+ end
33
+
23
34
  Marshal.load(serialized)
24
35
  end
25
36
 
@@ -50,13 +61,13 @@ module ActiveSupport
50
61
  end
51
62
 
52
63
  write.puts [result].pack("m")
53
- exit!
64
+ exit!(0)
54
65
  end
55
66
 
56
67
  write.close
57
68
  result = read.read
58
- Process.wait2(pid)
59
- result.unpack1("m")
69
+ _, status = Process.wait2(pid)
70
+ return status, result.unpack1("m")
60
71
  end
61
72
  end
62
73
  end
@@ -64,7 +75,7 @@ module ActiveSupport
64
75
  module Subprocess
65
76
  ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
66
77
 
67
- # Complicated H4X to get this working in windows / jruby with
78
+ # Complicated H4X to get this working in Windows / JRuby with
68
79
  # no forking.
69
80
  def run_in_isolation(&blk)
70
81
  require "tempfile"
@@ -75,7 +86,7 @@ module ActiveSupport
75
86
  File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
76
87
  file.puts [Marshal.dump(test_result)].pack("m")
77
88
  end
78
- exit!
89
+ exit!(0)
79
90
  else
80
91
  Tempfile.open("isolation") do |tmpfile|
81
92
  env = {
@@ -93,13 +104,14 @@ module ActiveSupport
93
104
 
94
105
  child = IO.popen([env, Gem.ruby, *load_path_args, $0, *ORIG_ARGV, test_opts])
95
106
 
107
+ status = nil
96
108
  begin
97
- Process.wait(child.pid)
109
+ _, status = Process.wait2(child.pid)
98
110
  rescue Errno::ECHILD # The child process may exit before we wait
99
111
  nil
100
112
  end
101
113
 
102
- return tmpfile.read.unpack1("m")
114
+ return status, tmpfile.read.unpack1("m")
103
115
  end
104
116
  end
105
117
  end
@@ -17,24 +17,23 @@ 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
+ def expect_called_with(mock, args, returns: false, **kwargs)
34
+ mock.expect(:call, returns, args, **kwargs)
35
+ end
36
+
38
37
  def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
39
38
  times_called = 0
40
39
  klass.define_method("stubbed_#{method_name}") do |*|
@@ -6,6 +6,8 @@ require "drb/unix" unless Gem.win_platform?
6
6
  module ActiveSupport
7
7
  module Testing
8
8
  class Parallelization # :nodoc:
9
+ PrerecordResultClass = Struct.new(:name)
10
+
9
11
  class Server
10
12
  include DRb::DRbUndumped
11
13
 
@@ -21,6 +23,7 @@ module ActiveSupport
21
23
  @in_flight.delete([result.klass, result.name])
22
24
 
23
25
  reporter.synchronize do
26
+ reporter.prerecord(PrerecordResultClass.new(result.klass), result.name)
24
27
  reporter.record(result)
25
28
  end
26
29
  end
@@ -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
@@ -46,6 +46,8 @@ module ActiveSupport
46
46
  run_callbacks :teardown
47
47
  rescue => e
48
48
  self.failures << Minitest::UnexpectedError.new(e)
49
+ rescue Minitest::Assertion => e
50
+ self.failures << e
49
51
  end
50
52
 
51
53
  super
@@ -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,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ $VERBOSE = true
4
+ Warning[:deprecated] = true
5
+
6
+ module ActiveSupport
7
+ module RaiseWarnings # :nodoc:
8
+ class WarningError < StandardError; end
9
+
10
+ PROJECT_ROOT = File.expand_path("../../../../", __dir__)
11
+ ALLOWED_WARNINGS = Regexp.union(
12
+ /circular require considered harmful.*delayed_job/, # Bug in delayed job.
13
+
14
+ # Expected non-verbose warning emitted by Rails.
15
+ /Ignoring .*\.yml because it has expired/,
16
+ /Failed to validate the schema cache because/,
17
+
18
+ # TODO: We need to decide what to do with this.
19
+ /Status code :unprocessable_entity is deprecated/
20
+ )
21
+
22
+ SUPPRESSED_WARNINGS = Regexp.union(
23
+ # TODO: remove if https://github.com/mikel/mail/pull/1557 or similar fix
24
+ %r{/lib/mail/parsers/.*statement not reached},
25
+ %r{/lib/mail/parsers/.*assigned but unused variable - disp_type_s},
26
+ %r{/lib/mail/parsers/.*assigned but unused variable - testEof}
27
+ )
28
+
29
+ def warn(message, ...)
30
+ return if SUPPRESSED_WARNINGS.match?(message)
31
+
32
+ super
33
+
34
+ return unless message.include?(PROJECT_ROOT)
35
+ return if ALLOWED_WARNINGS.match?(message)
36
+ return unless ENV["RAILS_STRICT_WARNINGS"] || ENV["BUILDKITE"]
37
+
38
+ raise WarningError.new(message)
39
+ end
40
+ end
41
+ end
42
+
43
+ Warning.singleton_class.prepend(ActiveSupport::RaiseWarnings)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ # Warns when a test case does not perform any assertions.
6
+ #
7
+ # This is helpful in detecting broken tests that do not perform intended assertions.
8
+ module TestsWithoutAssertions # :nodoc:
9
+ def after_teardown
10
+ super
11
+
12
+ if assertions.zero? && !skipped? && !error?
13
+ file, line = method(name).source_location
14
+ warn "Test is missing assertions: `#{name}` #{file}:#{line}"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "active_support/core_ext/module/redefine_method"
4
4
  require "active_support/core_ext/time/calculations"
5
- require "concurrent/map"
6
5
 
7
6
  module ActiveSupport
8
7
  module Testing
@@ -11,7 +10,7 @@ module ActiveSupport
11
10
  Stub = Struct.new(:object, :method_name, :original_method)
12
11
 
13
12
  def initialize
14
- @stubs = Concurrent::Map.new { |h, k| h[k] = {} }
13
+ @stubs = Hash.new { |h, k| h[k] = {} }
15
14
  end
16
15
 
17
16
  # Stubs object.method_name with the given block
@@ -26,7 +25,7 @@ module ActiveSupport
26
25
  unstub_object(stub)
27
26
  end
28
27
 
29
- new_name = "__simple_stub__#{method_name}"
28
+ new_name = "__simple_stub__#{method_name}__#{object_id}"
30
29
 
31
30
  @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
32
31
 
@@ -76,6 +75,11 @@ module ActiveSupport
76
75
  # stubbing +Time.now+, +Date.today+, and +DateTime.now+. The stubs are automatically removed
77
76
  # at the end of the test.
78
77
  #
78
+ # Note that the usec for the resulting time will be set to 0 to prevent rounding
79
+ # errors with external services, like MySQL (which will round instead of floor,
80
+ # leading to off-by-one-second errors), unless the <tt>with_usec</tt> argument
81
+ # is set to <tt>true</tt>.
82
+ #
79
83
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
80
84
  # travel 1.day
81
85
  # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
@@ -90,11 +94,11 @@ module ActiveSupport
90
94
  # User.create.created_at # => Sun, 10 Nov 2013 15:34:49 EST -05:00
91
95
  # end
92
96
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
93
- def travel(duration, &block)
94
- travel_to Time.now + duration, &block
97
+ def travel(duration, with_usec: false, &block)
98
+ travel_to Time.now + duration, with_usec: with_usec, &block
95
99
  end
96
100
 
97
- # Changes current time to the given time by stubbing +Time.now+,
101
+ # Changes current time to the given time by stubbing +Time.now+, +Time.new+,
98
102
  # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
99
103
  # The stubs are automatically removed at the end of the test.
100
104
  #
@@ -115,7 +119,8 @@ module ActiveSupport
115
119
  #
116
120
  # Note that the usec for the time passed will be set to 0 to prevent rounding
117
121
  # errors with external services, like MySQL (which will round instead of floor,
118
- # leading to off-by-one-second errors).
122
+ # leading to off-by-one-second errors), unless the <tt>with_usec</tt> argument
123
+ # is set to <tt>true</tt>.
119
124
  #
120
125
  # This method also accepts a block, which will return the current time back to its original
121
126
  # state at the end of the block:
@@ -125,7 +130,7 @@ module ActiveSupport
125
130
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
126
131
  # end
127
132
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
128
- def travel_to(date_or_time)
133
+ def travel_to(date_or_time, with_usec: false)
129
134
  if block_given? && in_block
130
135
  travel_to_nested_block_call = <<~MSG
131
136
 
@@ -159,13 +164,30 @@ module ActiveSupport
159
164
  elsif date_or_time.is_a?(String)
160
165
  now = Time.zone.parse(date_or_time)
161
166
  else
162
- now = date_or_time.to_time.change(usec: 0)
167
+ now = date_or_time
168
+ now = now.to_time unless now.is_a?(Time)
169
+ now = now.change(usec: 0) unless with_usec
170
+ end
171
+
172
+ # +now+ must be in local system timezone, because +Time.at(now)+
173
+ # and +now.to_date+ (see stubs below) will use +now+'s timezone too!
174
+ now = now.getlocal
175
+
176
+ stubs = simple_stubs
177
+ stubbed_time = Time.now if stubs.stubbing(Time, :now)
178
+ stubs.stub_object(Time, :now) { at(now) }
179
+
180
+ stubs.stub_object(Time, :new) do |*args, **options|
181
+ if args.empty? && options.empty?
182
+ at(now)
183
+ else
184
+ stub = stubs.stubbing(Time, :new)
185
+ Time.send(stub.original_method, *args, **options)
186
+ end
163
187
  end
164
188
 
165
- stubbed_time = Time.now if simple_stubs.stubbing(Time, :now)
166
- simple_stubs.stub_object(Time, :now) { at(now.to_i) }
167
- simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
168
- simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
189
+ stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
190
+ stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
169
191
 
170
192
  if block_given?
171
193
  begin
@@ -215,7 +237,7 @@ module ActiveSupport
215
237
  end
216
238
  alias_method :unfreeze_time, :travel_back
217
239
 
218
- # Calls +travel_to+ with +Time.now+.
240
+ # Calls +travel_to+ with +Time.now+. Forwards optional <tt>with_usec</tt> argument.
219
241
  #
220
242
  # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
221
243
  # freeze_time
@@ -231,8 +253,8 @@ module ActiveSupport
231
253
  # User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00
232
254
  # end
233
255
  # Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00
234
- def freeze_time(&block)
235
- travel_to Time.now, &block
256
+ def freeze_time(with_usec: false, &block)
257
+ travel_to Time.now, with_usec: with_usec, &block
236
258
  end
237
259
 
238
260
  private
@@ -8,6 +8,8 @@ require "active_support/core_ext/object/acts_like"
8
8
  require "active_support/core_ext/date_and_time/compatibility"
9
9
 
10
10
  module ActiveSupport
11
+ # = Active Support \Time With Zone
12
+ #
11
13
  # A Time-like class that can represent a time in any time zone. Necessary
12
14
  # because standard Ruby Time instances are limited to UTC and the
13
15
  # system's <tt>ENV['TZ']</tt> zone.
@@ -40,18 +42,6 @@ module ActiveSupport
40
42
  # t.is_a?(Time) # => true
41
43
  # t.is_a?(ActiveSupport::TimeWithZone) # => true
42
44
  class TimeWithZone
43
- # Report class name as 'Time' to thwart type checking.
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
-
52
- "Time"
53
- end
54
-
55
45
  PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N" }
56
46
  PRECISIONS[0] = "%FT%T"
57
47
 
@@ -78,7 +68,7 @@ module ActiveSupport
78
68
  alias_method :getutc, :utc
79
69
  alias_method :gmtime, :utc
80
70
 
81
- # Returns the underlying <tt>TZInfo::TimezonePeriod</tt>.
71
+ # Returns the underlying +TZInfo::TimezonePeriod+.
82
72
  def period
83
73
  @period ||= time_zone.period_for_utc(@utc)
84
74
  end
@@ -95,7 +85,7 @@ module ActiveSupport
95
85
  end
96
86
  alias_method :getlocal, :localtime
97
87
 
98
- # Returns true if the current time is within Daylight Savings Time for the
88
+ # Returns true if the current time is within Daylight Savings \Time for the
99
89
  # specified time zone.
100
90
  #
101
91
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
@@ -218,7 +208,7 @@ module ActiveSupport
218
208
  # Accepts an optional <tt>format</tt>:
219
209
  # * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
220
210
  # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_fs(:db).
221
- # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
211
+ # * Any key in +Time::DATE_FORMATS+ can be used. See active_support/core_ext/time/conversions.rb.
222
212
  def to_fs(format = :default)
223
213
  if format == :db
224
214
  utc.to_fs(format)
@@ -342,7 +332,7 @@ module ActiveSupport
342
332
  #
343
333
  def -(other)
344
334
  if other.acts_like?(:time)
345
- to_time - other.to_time
335
+ getutc - other.getutc
346
336
  elsif duration_of_variable_length?(other)
347
337
  method_missing(:-, other)
348
338
  else
@@ -385,8 +375,8 @@ module ActiveSupport
385
375
  #
386
376
  # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00
387
377
  # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15.116992711 EST -05:00
388
- # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.116992711 EST -05:00
389
- # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.116992711 EST -05:00
378
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.000000000 EST -05:00
379
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.000000000 EST -05:00
390
380
  # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
391
381
  # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
392
382
  def change(options)
@@ -516,6 +506,10 @@ module ActiveSupport
516
506
  false
517
507
  end
518
508
 
509
+ def present? # :nodoc:
510
+ true
511
+ end
512
+
519
513
  def freeze
520
514
  # preload instance variables before freezing
521
515
  period; utc; time; to_datetime; to_time