activesupport 6.0.0

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.

Files changed (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest/mock"
4
+
5
+ module ActiveSupport
6
+ module Testing
7
+ module MethodCallAssertions # :nodoc:
8
+ private
9
+ def assert_called(object, method_name, message = nil, times: 1, returns: nil)
10
+ times_called = 0
11
+
12
+ object.stub(method_name, proc { times_called += 1; returns }) { yield }
13
+
14
+ error = "Expected #{method_name} to be called #{times} times, " \
15
+ "but was called #{times_called} times"
16
+ error = "#{message}.\n#{error}" if message
17
+ assert_equal times, times_called, error
18
+ end
19
+
20
+ def assert_called_with(object, method_name, args, returns: nil)
21
+ mock = Minitest::Mock.new
22
+
23
+ if args.all? { |arg| arg.is_a?(Array) }
24
+ args.each { |arg| mock.expect(:call, returns, arg) }
25
+ else
26
+ mock.expect(:call, returns, args)
27
+ end
28
+
29
+ object.stub(method_name, mock) { yield }
30
+
31
+ mock.verify
32
+ end
33
+
34
+ def assert_not_called(object, method_name, message = nil, &block)
35
+ assert_called(object, method_name, message, times: 0, &block)
36
+ end
37
+
38
+ def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
39
+ times_called = 0
40
+ klass.define_method("stubbed_#{method_name}") do |*|
41
+ times_called += 1
42
+
43
+ returns
44
+ end
45
+
46
+ klass.alias_method "original_#{method_name}", method_name
47
+ klass.alias_method method_name, "stubbed_#{method_name}"
48
+
49
+ yield
50
+
51
+ error = "Expected #{method_name} to be called #{times} times, but was called #{times_called} times"
52
+ error = "#{message}.\n#{error}" if message
53
+
54
+ assert_equal times, times_called, error
55
+ ensure
56
+ klass.alias_method method_name, "original_#{method_name}"
57
+ klass.undef_method "original_#{method_name}"
58
+ klass.undef_method "stubbed_#{method_name}"
59
+ end
60
+
61
+ def assert_not_called_on_instance_of(klass, method_name, message = nil, &block)
62
+ assert_called_on_instance_of(klass, method_name, message, times: 0, &block)
63
+ end
64
+
65
+ def stub_any_instance(klass, instance: klass.new)
66
+ klass.stub(:new, instance) { yield instance }
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "drb"
4
+ require "drb/unix" unless Gem.win_platform?
5
+ require "active_support/core_ext/module/attribute_accessors"
6
+
7
+ module ActiveSupport
8
+ module Testing
9
+ class Parallelization # :nodoc:
10
+ class Server
11
+ include DRb::DRbUndumped
12
+
13
+ def initialize
14
+ @queue = Queue.new
15
+ end
16
+
17
+ def record(reporter, result)
18
+ raise DRb::DRbConnError if result.is_a?(DRb::DRbUnknown)
19
+
20
+ reporter.synchronize do
21
+ reporter.record(result)
22
+ end
23
+ end
24
+
25
+ def <<(o)
26
+ o[2] = DRbObject.new(o[2]) if o
27
+ @queue << o
28
+ end
29
+
30
+ def length
31
+ @queue.length
32
+ end
33
+
34
+ def pop; @queue.pop; end
35
+ end
36
+
37
+ @@after_fork_hooks = []
38
+
39
+ def self.after_fork_hook(&blk)
40
+ @@after_fork_hooks << blk
41
+ end
42
+
43
+ cattr_reader :after_fork_hooks
44
+
45
+ @@run_cleanup_hooks = []
46
+
47
+ def self.run_cleanup_hook(&blk)
48
+ @@run_cleanup_hooks << blk
49
+ end
50
+
51
+ cattr_reader :run_cleanup_hooks
52
+
53
+ def initialize(queue_size)
54
+ @queue_size = queue_size
55
+ @queue = Server.new
56
+ @pool = []
57
+
58
+ @url = DRb.start_service("drbunix:", @queue).uri
59
+ end
60
+
61
+ def after_fork(worker)
62
+ self.class.after_fork_hooks.each do |cb|
63
+ cb.call(worker)
64
+ end
65
+ end
66
+
67
+ def run_cleanup(worker)
68
+ self.class.run_cleanup_hooks.each do |cb|
69
+ cb.call(worker)
70
+ end
71
+ end
72
+
73
+ def start
74
+ @pool = @queue_size.times.map do |worker|
75
+ fork do
76
+ DRb.stop_service
77
+
78
+ begin
79
+ after_fork(worker)
80
+ rescue => setup_exception; end
81
+
82
+ queue = DRbObject.new_with_uri(@url)
83
+
84
+ while job = queue.pop
85
+ klass = job[0]
86
+ method = job[1]
87
+ reporter = job[2]
88
+ result = klass.with_info_handler reporter do
89
+ Minitest.run_one_method(klass, method)
90
+ end
91
+
92
+ add_setup_exception(result, setup_exception) if setup_exception
93
+
94
+ begin
95
+ queue.record(reporter, result)
96
+ rescue DRb::DRbConnError
97
+ result.failures.each do |failure|
98
+ failure.exception = DRb::DRbRemoteError.new(failure.exception)
99
+ end
100
+ queue.record(reporter, result)
101
+ end
102
+ end
103
+ ensure
104
+ run_cleanup(worker)
105
+ end
106
+ end
107
+ end
108
+
109
+ def <<(work)
110
+ @queue << work
111
+ end
112
+
113
+ def shutdown
114
+ @queue_size.times { @queue << nil }
115
+ @pool.each { |pid| Process.waitpid pid }
116
+
117
+ if @queue.length > 0
118
+ raise "Queue not empty, but all workers have finished. This probably means that a worker crashed and #{@queue.length} tests were missed."
119
+ end
120
+ end
121
+
122
+ private
123
+ def add_setup_exception(result, setup_exception)
124
+ result.failures.prepend Minitest::UnexpectedError.new(setup_exception)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/callbacks"
4
+
5
+ module ActiveSupport
6
+ module Testing
7
+ # Adds support for +setup+ and +teardown+ callbacks.
8
+ # These callbacks serve as a replacement to overwriting the
9
+ # <tt>#setup</tt> and <tt>#teardown</tt> methods of your TestCase.
10
+ #
11
+ # class ExampleTest < ActiveSupport::TestCase
12
+ # setup do
13
+ # # ...
14
+ # end
15
+ #
16
+ # teardown do
17
+ # # ...
18
+ # end
19
+ # end
20
+ module SetupAndTeardown
21
+ def self.prepended(klass)
22
+ klass.include ActiveSupport::Callbacks
23
+ klass.define_callbacks :setup, :teardown
24
+ klass.extend ClassMethods
25
+ end
26
+
27
+ module ClassMethods
28
+ # Add a callback, which runs before <tt>TestCase#setup</tt>.
29
+ def setup(*args, &block)
30
+ set_callback(:setup, :before, *args, &block)
31
+ end
32
+
33
+ # Add a callback, which runs after <tt>TestCase#teardown</tt>.
34
+ def teardown(*args, &block)
35
+ set_callback(:teardown, :after, *args, &block)
36
+ end
37
+ end
38
+
39
+ def before_setup # :nodoc:
40
+ super
41
+ run_callbacks :setup
42
+ end
43
+
44
+ def after_teardown # :nodoc:
45
+ begin
46
+ run_callbacks :teardown
47
+ rescue => e
48
+ self.failures << Minitest::UnexpectedError.new(e)
49
+ end
50
+
51
+ super
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module Stream #:nodoc:
6
+ private
7
+
8
+ def silence_stream(stream)
9
+ old_stream = stream.dup
10
+ stream.reopen(IO::NULL)
11
+ stream.sync = true
12
+ yield
13
+ ensure
14
+ stream.reopen(old_stream)
15
+ old_stream.close
16
+ end
17
+
18
+ def quietly
19
+ silence_stream(STDOUT) do
20
+ silence_stream(STDERR) do
21
+ yield
22
+ end
23
+ end
24
+ end
25
+
26
+ def capture(stream)
27
+ stream = stream.to_s
28
+ captured_stream = Tempfile.new(stream)
29
+ stream_io = eval("$#{stream}")
30
+ origin_stream = stream_io.dup
31
+ stream_io.reopen(captured_stream)
32
+
33
+ yield
34
+
35
+ stream_io.rewind
36
+ captured_stream.read
37
+ ensure
38
+ captured_stream.close
39
+ captured_stream.unlink
40
+ stream_io.reopen(origin_stream)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ # Logs a "PostsControllerTest: test name" heading before each test to
6
+ # make test.log easier to search and follow along with.
7
+ module TaggedLogging #:nodoc:
8
+ attr_writer :tagged_logger
9
+
10
+ def before_setup
11
+ if tagged_logger && tagged_logger.info?
12
+ heading = "#{self.class}: #{name}"
13
+ divider = "-" * heading.size
14
+ tagged_logger.info divider
15
+ tagged_logger.info heading
16
+ tagged_logger.info divider
17
+ end
18
+ super
19
+ end
20
+
21
+ private
22
+ def tagged_logger
23
+ @tagged_logger ||= (defined?(Rails.logger) && Rails.logger)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/redefine_method"
4
+ require "active_support/core_ext/time/calculations"
5
+ require "concurrent/map"
6
+
7
+ module ActiveSupport
8
+ module Testing
9
+ class SimpleStubs # :nodoc:
10
+ Stub = Struct.new(:object, :method_name, :original_method)
11
+
12
+ def initialize
13
+ @stubs = Concurrent::Map.new { |h, k| h[k] = {} }
14
+ end
15
+
16
+ def stub_object(object, method_name, &block)
17
+ if stub = stubbing(object, method_name)
18
+ unstub_object(stub)
19
+ end
20
+
21
+ new_name = "__simple_stub__#{method_name}"
22
+
23
+ @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
24
+
25
+ object.singleton_class.alias_method new_name, method_name
26
+ object.define_singleton_method(method_name, &block)
27
+ end
28
+
29
+ def unstub_all!
30
+ @stubs.each_value do |object_stubs|
31
+ object_stubs.each_value do |stub|
32
+ unstub_object(stub)
33
+ end
34
+ end
35
+ @stubs.clear
36
+ end
37
+
38
+ def stubbing(object, method_name)
39
+ @stubs[object.object_id][method_name]
40
+ end
41
+
42
+ private
43
+
44
+ def unstub_object(stub)
45
+ singleton_class = stub.object.singleton_class
46
+ singleton_class.silence_redefinition_of_method stub.method_name
47
+ singleton_class.alias_method stub.method_name, stub.original_method
48
+ singleton_class.undef_method stub.original_method
49
+ end
50
+ end
51
+
52
+ # Contains helpers that help you test passage of time.
53
+ module TimeHelpers
54
+ def after_teardown
55
+ travel_back
56
+ super
57
+ end
58
+
59
+ # Changes current time to the time in the future or in the past by a given time difference by
60
+ # stubbing +Time.now+, +Date.today+, and +DateTime.now+. The stubs are automatically removed
61
+ # at the end of the test.
62
+ #
63
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
64
+ # travel 1.day
65
+ # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
66
+ # Date.current # => Sun, 10 Nov 2013
67
+ # DateTime.current # => Sun, 10 Nov 2013 15:34:49 -0500
68
+ #
69
+ # This method also accepts a block, which will return the current time back to its original
70
+ # state at the end of the block:
71
+ #
72
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
73
+ # travel 1.day do
74
+ # User.create.created_at # => Sun, 10 Nov 2013 15:34:49 EST -05:00
75
+ # end
76
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
77
+ def travel(duration, &block)
78
+ travel_to Time.now + duration, &block
79
+ end
80
+
81
+ # Changes current time to the given time by stubbing +Time.now+,
82
+ # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
83
+ # The stubs are automatically removed at the end of the test.
84
+ #
85
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
86
+ # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
87
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
88
+ # Date.current # => Wed, 24 Nov 2004
89
+ # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
90
+ #
91
+ # Dates are taken as their timestamp at the beginning of the day in the
92
+ # application time zone. <tt>Time.current</tt> returns said timestamp,
93
+ # and <tt>Time.now</tt> its equivalent in the system time zone. Similarly,
94
+ # <tt>Date.current</tt> returns a date equal to the argument, and
95
+ # <tt>Date.today</tt> the date according to <tt>Time.now</tt>, which may
96
+ # be different. (Note that you rarely want to deal with <tt>Time.now</tt>,
97
+ # or <tt>Date.today</tt>, in order to honor the application time zone
98
+ # please always use <tt>Time.current</tt> and <tt>Date.current</tt>.)
99
+ #
100
+ # Note that the usec for the time passed will be set to 0 to prevent rounding
101
+ # errors with external services, like MySQL (which will round instead of floor,
102
+ # leading to off-by-one-second errors).
103
+ #
104
+ # This method also accepts a block, which will return the current time back to its original
105
+ # state at the end of the block:
106
+ #
107
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
108
+ # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do
109
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
110
+ # end
111
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
112
+ def travel_to(date_or_time)
113
+ if block_given? && simple_stubs.stubbing(Time, :now)
114
+ travel_to_nested_block_call = <<~MSG
115
+
116
+ Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
117
+
118
+ Instead of:
119
+
120
+ travel_to 2.days.from_now do
121
+ # 2 days from today
122
+ travel_to 3.days.from_now do
123
+ # 5 days from today
124
+ end
125
+ end
126
+
127
+ preferred way to achieve above is:
128
+
129
+ travel 2.days do
130
+ # 2 days from today
131
+ end
132
+
133
+ travel 5.days do
134
+ # 5 days from today
135
+ end
136
+
137
+ MSG
138
+ raise travel_to_nested_block_call
139
+ end
140
+
141
+ if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
142
+ now = date_or_time.midnight.to_time
143
+ else
144
+ now = date_or_time.to_time.change(usec: 0)
145
+ end
146
+
147
+ simple_stubs.stub_object(Time, :now) { at(now.to_i) }
148
+ simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
149
+ simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
150
+
151
+ if block_given?
152
+ begin
153
+ yield
154
+ ensure
155
+ travel_back
156
+ end
157
+ end
158
+ end
159
+
160
+ # Returns the current time back to its original state, by removing the stubs added by
161
+ # +travel+, +travel_to+, and +freeze_time+.
162
+ #
163
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
164
+ # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
165
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
166
+ # travel_back
167
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
168
+ def travel_back
169
+ simple_stubs.unstub_all!
170
+ end
171
+ alias_method :unfreeze_time, :travel_back
172
+
173
+ # Calls +travel_to+ with +Time.now+.
174
+ #
175
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
176
+ # freeze_time
177
+ # sleep(1)
178
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
179
+ #
180
+ # This method also accepts a block, which will return the current time back to its original
181
+ # state at the end of the block:
182
+ #
183
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
184
+ # freeze_time do
185
+ # sleep(1)
186
+ # User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00
187
+ # end
188
+ # Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00
189
+ def freeze_time(&block)
190
+ travel_to Time.now, &block
191
+ end
192
+
193
+ private
194
+
195
+ def simple_stubs
196
+ @simple_stubs ||= SimpleStubs.new
197
+ end
198
+ end
199
+ end
200
+ end