activesupport 1.2.4 → 8.1.2

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 (309) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +505 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support/actionable_error.rb +50 -0
  6. data/lib/active_support/all.rb +5 -0
  7. data/lib/active_support/array_inquirer.rb +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +234 -0
  9. data/lib/active_support/benchmark.rb +21 -0
  10. data/lib/active_support/benchmarkable.rb +53 -0
  11. data/lib/active_support/broadcast_logger.rb +238 -0
  12. data/lib/active_support/builder.rb +8 -0
  13. data/lib/active_support/cache/coder.rb +153 -0
  14. data/lib/active_support/cache/entry.rb +134 -0
  15. data/lib/active_support/cache/file_store.rb +244 -0
  16. data/lib/active_support/cache/mem_cache_store.rb +288 -0
  17. data/lib/active_support/cache/memory_store.rb +264 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +498 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +246 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1170 -0
  24. data/lib/active_support/callbacks.rb +960 -0
  25. data/lib/active_support/class_attribute.rb +33 -0
  26. data/lib/active_support/code_generator.rb +79 -0
  27. data/lib/active_support/concern.rb +217 -0
  28. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  29. data/lib/active_support/concurrency/null_lock.rb +13 -0
  30. data/lib/active_support/concurrency/share_lock.rb +225 -0
  31. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  32. data/lib/active_support/configurable.rb +193 -0
  33. data/lib/active_support/configuration_file.rb +60 -0
  34. data/lib/active_support/continuous_integration.rb +145 -0
  35. data/lib/active_support/core_ext/array/access.rb +100 -0
  36. data/lib/active_support/core_ext/array/conversions.rb +209 -26
  37. data/lib/active_support/core_ext/array/extract.rb +21 -0
  38. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  39. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  40. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  41. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  42. data/lib/active_support/core_ext/array.rb +8 -4
  43. data/lib/active_support/core_ext/benchmark.rb +6 -0
  44. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  45. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  46. data/lib/active_support/core_ext/class/attribute.rb +137 -0
  47. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  48. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  49. data/lib/active_support/core_ext/class.rb +4 -0
  50. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  51. data/lib/active_support/core_ext/date/blank.rb +18 -0
  52. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  53. data/lib/active_support/core_ext/date/conversions.rb +95 -28
  54. data/lib/active_support/core_ext/date/zones.rb +8 -0
  55. data/lib/active_support/core_ext/date.rb +6 -5
  56. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  57. data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
  58. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  59. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  60. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  62. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  63. data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
  64. data/lib/active_support/core_ext/date_time.rb +7 -0
  65. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  66. data/lib/active_support/core_ext/digest.rb +3 -0
  67. data/lib/active_support/core_ext/enumerable.rb +277 -7
  68. data/lib/active_support/core_ext/erb/util.rb +201 -0
  69. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  70. data/lib/active_support/core_ext/file.rb +3 -0
  71. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  72. data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
  73. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  74. data/lib/active_support/core_ext/hash/except.rb +12 -0
  75. data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
  76. data/lib/active_support/core_ext/hash/keys.rb +134 -44
  77. data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
  78. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  79. data/lib/active_support/core_ext/hash.rb +9 -8
  80. data/lib/active_support/core_ext/integer/inflections.rb +29 -13
  81. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  82. data/lib/active_support/core_ext/integer/time.rb +22 -0
  83. data/lib/active_support/core_ext/integer.rb +4 -6
  84. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  85. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  86. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  87. data/lib/active_support/core_ext/kernel.rb +4 -78
  88. data/lib/active_support/core_ext/load_error.rb +6 -35
  89. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  90. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  91. data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
  92. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  93. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  94. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  95. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  96. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  97. data/lib/active_support/core_ext/module/introspection.rb +65 -0
  98. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  99. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  100. data/lib/active_support/core_ext/module.rb +13 -0
  101. data/lib/active_support/core_ext/name_error.rb +59 -0
  102. data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
  103. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  104. data/lib/active_support/core_ext/numeric/time.rb +64 -57
  105. data/lib/active_support/core_ext/numeric.rb +4 -6
  106. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  107. data/lib/active_support/core_ext/object/blank.rb +199 -0
  108. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  109. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  110. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  111. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  112. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  113. data/lib/active_support/core_ext/object/json.rb +267 -0
  114. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  115. data/lib/active_support/core_ext/object/to_query.rb +93 -0
  116. data/lib/active_support/core_ext/object/try.rb +158 -0
  117. data/lib/active_support/core_ext/object/with.rb +46 -0
  118. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  119. data/lib/active_support/core_ext/object.rb +17 -0
  120. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  121. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  122. data/lib/active_support/core_ext/pathname.rb +4 -0
  123. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  124. data/lib/active_support/core_ext/range/conversions.rb +58 -17
  125. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  126. data/lib/active_support/core_ext/range/sole.rb +17 -0
  127. data/lib/active_support/core_ext/range.rb +5 -4
  128. data/lib/active_support/core_ext/regexp.rb +14 -0
  129. data/lib/active_support/core_ext/securerandom.rb +57 -0
  130. data/lib/active_support/core_ext/string/access.rb +93 -56
  131. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  132. data/lib/active_support/core_ext/string/conversions.rb +57 -16
  133. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  134. data/lib/active_support/core_ext/string/filters.rb +151 -0
  135. data/lib/active_support/core_ext/string/indent.rb +45 -0
  136. data/lib/active_support/core_ext/string/inflections.rb +297 -54
  137. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  138. data/lib/active_support/core_ext/string/multibyte.rb +67 -0
  139. data/lib/active_support/core_ext/string/output_safety.rb +235 -0
  140. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
  141. data/lib/active_support/core_ext/string/strip.rb +27 -0
  142. data/lib/active_support/core_ext/string/zones.rb +16 -0
  143. data/lib/active_support/core_ext/string.rb +14 -10
  144. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  145. data/lib/active_support/core_ext/symbol.rb +3 -0
  146. data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
  147. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  148. data/lib/active_support/core_ext/time/calculations.rb +358 -153
  149. data/lib/active_support/core_ext/time/compatibility.rb +15 -0
  150. data/lib/active_support/core_ext/time/conversions.rb +69 -30
  151. data/lib/active_support/core_ext/time/zones.rb +97 -0
  152. data/lib/active_support/core_ext/time.rb +6 -6
  153. data/lib/active_support/core_ext.rb +5 -1
  154. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  155. data/lib/active_support/current_attributes.rb +243 -0
  156. data/lib/active_support/deep_mergeable.rb +53 -0
  157. data/lib/active_support/delegation.rb +183 -0
  158. data/lib/active_support/dependencies/autoload.rb +72 -0
  159. data/lib/active_support/dependencies/interlock.rb +55 -0
  160. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  161. data/lib/active_support/dependencies.rb +84 -222
  162. data/lib/active_support/deprecation/behaviors.rb +148 -0
  163. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  164. data/lib/active_support/deprecation/deprecators.rb +104 -0
  165. data/lib/active_support/deprecation/disallowed.rb +54 -0
  166. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  167. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  168. data/lib/active_support/deprecation/reporting.rb +162 -0
  169. data/lib/active_support/deprecation.rb +81 -0
  170. data/lib/active_support/deprecator.rb +7 -0
  171. data/lib/active_support/descendants_tracker.rb +112 -0
  172. data/lib/active_support/digest.rb +22 -0
  173. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  174. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  175. data/lib/active_support/duration.rb +524 -0
  176. data/lib/active_support/editor.rb +70 -0
  177. data/lib/active_support/encrypted_configuration.rb +126 -0
  178. data/lib/active_support/encrypted_file.rb +133 -0
  179. data/lib/active_support/environment_inquirer.rb +40 -0
  180. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  181. data/lib/active_support/error_reporter.rb +318 -0
  182. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  183. data/lib/active_support/event_reporter.rb +592 -0
  184. data/lib/active_support/evented_file_update_checker.rb +185 -0
  185. data/lib/active_support/execution_context/test_helper.rb +13 -0
  186. data/lib/active_support/execution_context.rb +110 -0
  187. data/lib/active_support/execution_wrapper.rb +150 -0
  188. data/lib/active_support/executor/test_helper.rb +7 -0
  189. data/lib/active_support/executor.rb +8 -0
  190. data/lib/active_support/file_update_checker.rb +166 -0
  191. data/lib/active_support/fork_tracker.rb +43 -0
  192. data/lib/active_support/gem_version.rb +17 -0
  193. data/lib/active_support/gzip.rb +41 -0
  194. data/lib/active_support/hash_with_indifferent_access.rb +464 -0
  195. data/lib/active_support/html_safe_translation.rb +56 -0
  196. data/lib/active_support/i18n.rb +17 -0
  197. data/lib/active_support/i18n_railtie.rb +140 -0
  198. data/lib/active_support/inflections.rb +68 -49
  199. data/lib/active_support/inflector/inflections.rb +290 -0
  200. data/lib/active_support/inflector/methods.rb +387 -0
  201. data/lib/active_support/inflector/transliterate.rb +147 -0
  202. data/lib/active_support/inflector.rb +7 -164
  203. data/lib/active_support/isolated_execution_state.rb +76 -0
  204. data/lib/active_support/json/decoding.rb +78 -0
  205. data/lib/active_support/json/encoding.rb +256 -0
  206. data/lib/active_support/json.rb +4 -0
  207. data/lib/active_support/key_generator.rb +66 -0
  208. data/lib/active_support/lazy_load_hooks.rb +107 -0
  209. data/lib/active_support/locale/en.rb +33 -0
  210. data/lib/active_support/locale/en.yml +141 -0
  211. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  212. data/lib/active_support/log_subscriber.rb +188 -0
  213. data/lib/active_support/logger.rb +55 -0
  214. data/lib/active_support/logger_silence.rb +21 -0
  215. data/lib/active_support/logger_thread_safe_level.rb +50 -0
  216. data/lib/active_support/message_encryptor.rb +374 -0
  217. data/lib/active_support/message_encryptors.rb +193 -0
  218. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  219. data/lib/active_support/message_pack/extensions.rb +310 -0
  220. data/lib/active_support/message_pack/serializer.rb +63 -0
  221. data/lib/active_support/message_pack.rb +50 -0
  222. data/lib/active_support/message_verifier.rb +377 -0
  223. data/lib/active_support/message_verifiers.rb +189 -0
  224. data/lib/active_support/messages/codec.rb +65 -0
  225. data/lib/active_support/messages/metadata.rb +146 -0
  226. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  227. data/lib/active_support/messages/rotation_coordinator.rb +102 -0
  228. data/lib/active_support/messages/rotator.rb +69 -0
  229. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  230. data/lib/active_support/multibyte/chars.rb +188 -0
  231. data/lib/active_support/multibyte/unicode.rb +42 -0
  232. data/lib/active_support/multibyte.rb +27 -0
  233. data/lib/active_support/notifications/fanout.rb +467 -0
  234. data/lib/active_support/notifications/instrumenter.rb +240 -0
  235. data/lib/active_support/notifications.rb +281 -0
  236. data/lib/active_support/number_helper/number_converter.rb +190 -0
  237. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  238. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  239. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  240. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  241. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  242. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  243. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  244. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  245. data/lib/active_support/number_helper.rb +479 -0
  246. data/lib/active_support/option_merger.rb +38 -0
  247. data/lib/active_support/ordered_hash.rb +50 -0
  248. data/lib/active_support/ordered_options.rb +141 -25
  249. data/lib/active_support/parameter_filter.rb +157 -0
  250. data/lib/active_support/rails.rb +26 -0
  251. data/lib/active_support/railtie.rb +180 -0
  252. data/lib/active_support/reloader.rb +138 -0
  253. data/lib/active_support/rescuable.rb +176 -0
  254. data/lib/active_support/secure_compare_rotator.rb +58 -0
  255. data/lib/active_support/security_utils.rb +38 -0
  256. data/lib/active_support/string_inquirer.rb +35 -0
  257. data/lib/active_support/structured_event_subscriber.rb +99 -0
  258. data/lib/active_support/subscriber.rb +141 -0
  259. data/lib/active_support/syntax_error_proxy.rb +67 -0
  260. data/lib/active_support/tagged_logging.rb +157 -0
  261. data/lib/active_support/test_case.rb +365 -0
  262. data/lib/active_support/testing/assertions.rb +369 -0
  263. data/lib/active_support/testing/autorun.rb +10 -0
  264. data/lib/active_support/testing/constant_lookup.rb +51 -0
  265. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  266. data/lib/active_support/testing/declarative.rb +28 -0
  267. data/lib/active_support/testing/deprecation.rb +82 -0
  268. data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
  269. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  270. data/lib/active_support/testing/file_fixtures.rb +38 -0
  271. data/lib/active_support/testing/isolation.rb +121 -0
  272. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  273. data/lib/active_support/testing/notification_assertions.rb +92 -0
  274. data/lib/active_support/testing/parallelization/server.rb +98 -0
  275. data/lib/active_support/testing/parallelization/worker.rb +107 -0
  276. data/lib/active_support/testing/parallelization.rb +79 -0
  277. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  278. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  279. data/lib/active_support/testing/stream.rb +41 -0
  280. data/lib/active_support/testing/tagged_logging.rb +27 -0
  281. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  282. data/lib/active_support/testing/time_helpers.rb +273 -0
  283. data/lib/active_support/time.rb +20 -0
  284. data/lib/active_support/time_with_zone.rb +613 -0
  285. data/lib/active_support/values/time_zone.rb +599 -158
  286. data/lib/active_support/version.rb +7 -6
  287. data/lib/active_support/xml_mini/jdom.rb +175 -0
  288. data/lib/active_support/xml_mini/libxml.rb +80 -0
  289. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  290. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  291. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  292. data/lib/active_support/xml_mini/rexml.rb +137 -0
  293. data/lib/active_support/xml_mini.rb +212 -0
  294. data/lib/active_support.rb +122 -10
  295. metadata +524 -93
  296. data/CHANGELOG +0 -283
  297. data/lib/active_support/binding_of_caller.rb +0 -84
  298. data/lib/active_support/breakpoint.rb +0 -523
  299. data/lib/active_support/class_attribute_accessors.rb +0 -57
  300. data/lib/active_support/class_inheritable_attributes.rb +0 -117
  301. data/lib/active_support/clean_logger.rb +0 -36
  302. data/lib/active_support/core_ext/blank.rb +0 -38
  303. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
  304. data/lib/active_support/core_ext/cgi.rb +0 -5
  305. data/lib/active_support/core_ext/exception.rb +0 -29
  306. data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
  307. data/lib/active_support/core_ext/object_and_class.rb +0 -44
  308. data/lib/active_support/module_attribute_accessors.rb +0 -57
  309. data/lib/active_support/whiny_nil.rb +0 -38
@@ -0,0 +1,369 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/enumerable"
4
+
5
+ module ActiveSupport
6
+ module Testing
7
+ module Assertions
8
+ UNTRACKED = Object.new # :nodoc:
9
+
10
+ # Asserts that an expression is not truthy. Passes if +object+ is +nil+ or
11
+ # +false+. "Truthy" means "considered true in a conditional" like <tt>if
12
+ # foo</tt>.
13
+ #
14
+ # assert_not nil # => true
15
+ # assert_not false # => true
16
+ # assert_not 'foo' # => Expected "foo" to be nil or false
17
+ #
18
+ # An error message can be specified.
19
+ #
20
+ # assert_not foo, 'foo should be false'
21
+ def assert_not(object, message = nil)
22
+ message ||= -> { "Expected #{mu_pp(object)} to be nil or false" }
23
+ assert !object, message
24
+ end
25
+
26
+ # Asserts that a block raises one of +exp+. This is an enhancement of the
27
+ # standard Minitest assertion method with the ability to test error
28
+ # messages.
29
+ #
30
+ # assert_raises(ArgumentError, match: /incorrect param/i) do
31
+ # perform_service(param: 'exception')
32
+ # end
33
+ #
34
+ def assert_raises(*exp, match: nil, &block)
35
+ error = super(*exp, &block)
36
+ assert_match(match, error.message) if match
37
+ error
38
+ end
39
+ alias :assert_raise :assert_raises
40
+
41
+ # Assertion that the block should not raise an exception.
42
+ #
43
+ # Passes if evaluated code in the yielded block raises no exception.
44
+ #
45
+ # assert_nothing_raised do
46
+ # perform_service(param: 'no_exception')
47
+ # end
48
+ def assert_nothing_raised
49
+ yield.tap { assert(true) }
50
+ rescue => error
51
+ raise Minitest::UnexpectedError.new(error)
52
+ end
53
+
54
+ # Test numeric difference between the return value of an expression as a
55
+ # result of what is evaluated in the yielded block.
56
+ #
57
+ # assert_difference 'Article.count' do
58
+ # post :create, params: { article: {...} }
59
+ # end
60
+ #
61
+ # An arbitrary expression is passed in and evaluated.
62
+ #
63
+ # assert_difference 'Article.last.comments(:reload).size' do
64
+ # post :create, params: { comment: {...} }
65
+ # end
66
+ #
67
+ # An arbitrary positive or negative difference can be specified.
68
+ # The default is +1+.
69
+ #
70
+ # assert_difference 'Article.count', -1 do
71
+ # post :delete, params: { id: ... }
72
+ # end
73
+ #
74
+ # An array of expressions can be passed in and evaluated.
75
+ #
76
+ # assert_difference [ 'Article.count', 'Post.count' ], 2 do
77
+ # post :create, params: { article: {...} }
78
+ # end
79
+ #
80
+ # A hash of expressions/numeric differences can be passed in and evaluated.
81
+ #
82
+ # assert_difference({ 'Article.count' => 1, 'Notification.count' => 2 }) do
83
+ # post :create, params: { article: {...} }
84
+ # end
85
+ #
86
+ # A lambda, a list of lambdas or a hash of lambdas/numeric differences can be passed in and evaluated:
87
+ #
88
+ # assert_difference ->{ Article.count }, 2 do
89
+ # post :create, params: { article: {...} }
90
+ # end
91
+ #
92
+ # assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
93
+ # post :create, params: { article: {...} }
94
+ # end
95
+ #
96
+ # assert_difference ->{ Article.count } => 1, ->{ Notification.count } => 2 do
97
+ # post :create, params: { article: {...} }
98
+ # end
99
+ #
100
+ # An error message can be specified.
101
+ #
102
+ # assert_difference 'Article.count', -1, 'An Article should be destroyed' do
103
+ # post :delete, params: { id: ... }
104
+ # end
105
+ def assert_difference(expression, *args, &block)
106
+ expressions =
107
+ if expression.is_a?(Hash)
108
+ message = args[0]
109
+ expression
110
+ else
111
+ difference = args[0] || 1
112
+ message = args[1]
113
+ Array(expression).index_with(difference)
114
+ end
115
+
116
+ exps = expressions.keys.map { |e|
117
+ e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
118
+ }
119
+ before = exps.map(&:call)
120
+
121
+ retval = _assert_nothing_raised_or_warn("assert_difference", &block)
122
+
123
+ expressions.zip(exps, before) do |(code, diff), exp, before_value|
124
+ actual = exp.call
125
+ rich_message = -> do
126
+ code_string = code.respond_to?(:call) ? _callable_to_source_string(code) : code
127
+ error = "`#{code_string}` didn't change by #{diff}, but by #{actual - before_value}."
128
+ error = "#{error}\n#{diff before_value + diff, actual}" if Minitest::VERSION > "6"
129
+ error = "#{message}.\n#{error}" if message
130
+ error
131
+ end
132
+ assert_equal(before_value + diff, actual, rich_message)
133
+ end
134
+
135
+ retval
136
+ end
137
+
138
+ # Assertion that the numeric result of evaluating an expression is not
139
+ # changed before and after invoking the passed in block.
140
+ #
141
+ # assert_no_difference 'Article.count' do
142
+ # post :create, params: { article: invalid_attributes }
143
+ # end
144
+ #
145
+ # A lambda can be passed in and evaluated.
146
+ #
147
+ # assert_no_difference -> { Article.count } do
148
+ # post :create, params: { article: invalid_attributes }
149
+ # end
150
+ #
151
+ # An error message can be specified.
152
+ #
153
+ # assert_no_difference 'Article.count', 'An Article should not be created' do
154
+ # post :create, params: { article: invalid_attributes }
155
+ # end
156
+ #
157
+ # An array of expressions can also be passed in and evaluated.
158
+ #
159
+ # assert_no_difference [ 'Article.count', -> { Post.count } ] do
160
+ # post :create, params: { article: invalid_attributes }
161
+ # end
162
+ def assert_no_difference(expression, message = nil, &block)
163
+ assert_difference expression, 0, message, &block
164
+ end
165
+
166
+ # Assertion that the result of evaluating an expression is changed before
167
+ # and after invoking the passed in block.
168
+ #
169
+ # assert_changes 'Status.all_good?' do
170
+ # post :create, params: { status: { ok: false } }
171
+ # end
172
+ #
173
+ # You can pass the block as a string to be evaluated in the context of
174
+ # the block. A lambda can be passed for the block as well.
175
+ #
176
+ # assert_changes -> { Status.all_good? } do
177
+ # post :create, params: { status: { ok: false } }
178
+ # end
179
+ #
180
+ # The assertion is useful to test side effects. The passed block can be
181
+ # anything that can be converted to string with #to_s.
182
+ #
183
+ # assert_changes :@object do
184
+ # @object = 42
185
+ # end
186
+ #
187
+ # The keyword arguments +:from+ and +:to+ can be given to specify the
188
+ # expected initial value and the expected value after the block was
189
+ # executed. The comparison is done using case equality (===), which means
190
+ # you can specify patterns or classes:
191
+ #
192
+ # # Exact value match
193
+ # assert_changes :@object, from: nil, to: :foo do
194
+ # @object = :foo
195
+ # end
196
+ #
197
+ # # Case equality
198
+ # assert_changes -> { user.token }, to: /\w{32}/ do
199
+ # user.generate_token
200
+ # end
201
+ #
202
+ # # Type check
203
+ # assert_changes -> { current_error }, from: nil, to: RuntimeError do
204
+ # raise "Oops"
205
+ # end
206
+ #
207
+ # An error message can be specified.
208
+ #
209
+ # assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do
210
+ # post :create, params: { status: { incident: true } }
211
+ # end
212
+ def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block)
213
+ exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
214
+
215
+ before = exp.call
216
+ retval = _assert_nothing_raised_or_warn("assert_changes", &block)
217
+
218
+ unless from == UNTRACKED
219
+ rich_message = -> do
220
+ error = "Expected change from #{from.inspect}, got #{before.inspect}"
221
+ error = "#{message}.\n#{error}" if message
222
+ error
223
+ end
224
+ assert from === before, rich_message
225
+ end
226
+
227
+ after = exp.call
228
+
229
+ rich_message = -> do
230
+ code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
231
+ error = "`#{code_string}` didn't change"
232
+ error = "#{error}. It was already #{to.inspect}." if before == to
233
+ error = "#{message}.\n#{error}" if message
234
+ error
235
+ end
236
+ refute_equal before, after, rich_message
237
+
238
+ unless to == UNTRACKED
239
+ rich_message = -> do
240
+ error = "Expected change to #{to.inspect}, got #{after.inspect}\n"
241
+ error = "#{message}.\n#{error}" if message
242
+ error
243
+ end
244
+ assert to === after, rich_message
245
+ end
246
+
247
+ retval
248
+ end
249
+
250
+ # Assertion that the result of evaluating an expression is not changed before
251
+ # and after invoking the passed in block.
252
+ #
253
+ # assert_no_changes 'Status.all_good?' do
254
+ # post :create, params: { status: { ok: true } }
255
+ # end
256
+ #
257
+ # Provide the optional keyword argument +:from+ to specify the expected
258
+ # initial value. The comparison is done using case equality (===), which means
259
+ # you can specify patterns or classes:
260
+ #
261
+ # # Exact value match
262
+ # assert_no_changes -> { Status.all_good? }, from: true do
263
+ # post :create, params: { status: { ok: true } }
264
+ # end
265
+ #
266
+ # # Case equality
267
+ # assert_no_changes -> { user.token }, from: /\w{32}/ do
268
+ # user.touch
269
+ # end
270
+ #
271
+ # # Type check
272
+ # assert_no_changes -> { current_error }, from: RuntimeError do
273
+ # retry_operation
274
+ # end
275
+ #
276
+ # An error message can be specified.
277
+ #
278
+ # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
279
+ # post :create, params: { status: { ok: false } }
280
+ # end
281
+ def assert_no_changes(expression, message = nil, from: UNTRACKED, &block)
282
+ exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
283
+
284
+ before = exp.call
285
+ retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
286
+
287
+ unless from == UNTRACKED
288
+ rich_message = -> do
289
+ error = "Expected initial value of #{from.inspect}, got #{before.inspect}"
290
+ error = "#{message}.\n#{error}" if message
291
+ error
292
+ end
293
+ assert from === before, rich_message
294
+ end
295
+
296
+ after = exp.call
297
+
298
+ rich_message = -> do
299
+ code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
300
+ error = "`#{code_string}` changed."
301
+ error = "#{message}.\n#{error}" if message
302
+ error = "#{error}\n#{diff before, after}" if Minitest::VERSION > "6"
303
+ error
304
+ end
305
+
306
+ if before.nil?
307
+ assert_nil after, rich_message
308
+ else
309
+ assert_equal before, after, rich_message
310
+ end
311
+
312
+ retval
313
+ end
314
+
315
+ private
316
+ def _assert_nothing_raised_or_warn(assertion, &block)
317
+ assert_nothing_raised(&block)
318
+ rescue Minitest::UnexpectedError => e
319
+ if tagged_logger && tagged_logger.warn?
320
+ warning = <<~MSG
321
+ #{self.class} - #{name}: #{e.error.class} raised.
322
+ If you expected this exception, use `assert_raises` as near to the code that raises as possible.
323
+ Other block based assertions (e.g. `#{assertion}`) can be used, as long as `assert_raises` is inside their block.
324
+ MSG
325
+ tagged_logger.warn warning
326
+ end
327
+
328
+ raise
329
+ end
330
+
331
+ def _callable_to_source_string(callable)
332
+ if defined?(RubyVM::InstructionSequence) && callable.is_a?(Proc)
333
+ iseq = RubyVM::InstructionSequence.of(callable)
334
+ source =
335
+ if iseq.script_lines
336
+ iseq.script_lines.join("\n")
337
+ elsif File.readable?(iseq.absolute_path)
338
+ File.read(iseq.absolute_path)
339
+ end
340
+
341
+ return callable unless source
342
+
343
+ location = iseq.to_a[4][:code_location]
344
+ return callable unless location
345
+
346
+ lines = source.lines[(location[0] - 1)..(location[2] - 1)]
347
+ lines[-1] = lines[-1].byteslice(...location[3])
348
+ lines[0] = lines[0].byteslice(location[1]...)
349
+ source = lines.join.strip
350
+
351
+ # We ignore procs defined with do/end as they are likely multi-line anyway.
352
+ if source.start_with?("{")
353
+ source.delete_suffix!("}")
354
+ source.delete_prefix!("{")
355
+ source.strip!
356
+ # It won't read nice if the callable contains multiple
357
+ # lines, and it should be a rare occurrence anyway.
358
+ # Same if it takes arguments.
359
+ if !source.include?("\n") && !source.start_with?("|")
360
+ return source
361
+ end
362
+ end
363
+ end
364
+
365
+ callable
366
+ end
367
+ end
368
+ end
369
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest"
4
+
5
+ # This respond_to check handles tests running sub-processes in an
6
+ # unbundled environment, which triggers MT5 usage. This conditional may
7
+ # be removable after the version bump, though it currently safeguards
8
+ # against issues in environments with multiple versions installed.
9
+ Minitest.load :rails if Minitest.respond_to? :load
10
+ Minitest.autorun
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/inflector"
5
+
6
+ module ActiveSupport
7
+ module Testing
8
+ # Resolves a constant from a minitest spec name.
9
+ #
10
+ # Given the following spec-style test:
11
+ #
12
+ # describe WidgetsController, :index do
13
+ # describe "authenticated user" do
14
+ # describe "returns widgets" do
15
+ # it "has a controller that exists" do
16
+ # assert_kind_of WidgetsController, @controller
17
+ # end
18
+ # end
19
+ # end
20
+ # end
21
+ #
22
+ # The test will have the following name:
23
+ #
24
+ # "WidgetsController::index::authenticated user::returns widgets"
25
+ #
26
+ # The constant WidgetsController can be resolved from the name.
27
+ # The following code will resolve the constant:
28
+ #
29
+ # controller = determine_constant_from_test_name(name) do |constant|
30
+ # Class === constant && constant < ::ActionController::Metal
31
+ # end
32
+ module ConstantLookup
33
+ extend ::ActiveSupport::Concern
34
+
35
+ module ClassMethods # :nodoc:
36
+ def determine_constant_from_test_name(test_name)
37
+ names = test_name.split "::"
38
+ while names.size > 0 do
39
+ names.last.sub!(/Test$/, "")
40
+ begin
41
+ constant = names.join("::").safe_constantize
42
+ break(constant) if yield(constant)
43
+ ensure
44
+ names.pop
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module ConstantStubbing
6
+ # Changes the value of a constant for the duration of a block. Example:
7
+ #
8
+ # # World::List::Import::LARGE_IMPORT_THRESHOLD = 5000
9
+ # stub_const(World::List::Import, :LARGE_IMPORT_THRESHOLD, 1) do
10
+ # assert_equal 1, World::List::Import::LARGE_IMPORT_THRESHOLD
11
+ # end
12
+ #
13
+ # assert_equal 5000, World::List::Import::LARGE_IMPORT_THRESHOLD
14
+ #
15
+ # Using this method rather than forcing <tt>World::List::Import::LARGE_IMPORT_THRESHOLD = 5000</tt> prevents
16
+ # warnings from being thrown, and ensures that the old value is returned after the test has completed.
17
+ #
18
+ # If the constant doesn't already exists, but you need it set for the duration of the block
19
+ # you can do so by passing `exists: false`.
20
+ #
21
+ # stub_const(object, :SOME_CONST, 1, exists: false) do
22
+ # assert_equal 1, SOME_CONST
23
+ # end
24
+ #
25
+ # Note: Stubbing a const will stub it across all threads. So if you have concurrent threads
26
+ # (like separate test suites running in parallel) that all depend on the same constant, it's possible
27
+ # divergent stubbing will trample on each other.
28
+ def stub_const(mod, constant, new_value, exists: true)
29
+ if exists
30
+ begin
31
+ old_value = mod.const_get(constant, false)
32
+ mod.send(:remove_const, constant)
33
+ mod.const_set(constant, new_value)
34
+ yield
35
+ ensure
36
+ mod.send(:remove_const, constant)
37
+ mod.const_set(constant, old_value)
38
+ end
39
+ else
40
+ if mod.const_defined?(constant)
41
+ raise NameError, "already defined constant #{constant} in #{mod.name}"
42
+ end
43
+
44
+ begin
45
+ mod.const_set(constant, new_value)
46
+ yield
47
+ ensure
48
+ mod.send(:remove_const, constant)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module Declarative
6
+ unless defined?(Spec)
7
+ # Helper to define a test method using a String. Under the hood, it replaces
8
+ # spaces with underscores and defines the test method.
9
+ #
10
+ # test "verify something" do
11
+ # ...
12
+ # end
13
+ def test(name, &block)
14
+ test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
15
+ defined = method_defined? test_name
16
+ raise "#{test_name} is already defined in #{self}" if defined
17
+ if block_given?
18
+ define_method(test_name, &block)
19
+ else
20
+ define_method(test_name) do
21
+ flunk "No implementation provided for #{name}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deprecation"
4
+
5
+ module ActiveSupport
6
+ module Testing
7
+ module Deprecation
8
+ ##
9
+ # :call-seq:
10
+ # assert_deprecated(deprecator, &block)
11
+ # assert_deprecated(match, deprecator, &block)
12
+ #
13
+ # Asserts that a matching deprecation warning was emitted by the given deprecator during the execution of the yielded block.
14
+ #
15
+ # assert_deprecated(/foo/, CustomDeprecator) do
16
+ # CustomDeprecator.warn "foo should no longer be used"
17
+ # end
18
+ #
19
+ # The +match+ object may be a +Regexp+, or +String+ appearing in the message.
20
+ #
21
+ # assert_deprecated('foo', CustomDeprecator) do
22
+ # CustomDeprecator.warn "foo should no longer be used"
23
+ # end
24
+ #
25
+ # If the +match+ is omitted (or explicitly +nil+), any deprecation warning will match.
26
+ #
27
+ # assert_deprecated(CustomDeprecator) do
28
+ # CustomDeprecator.warn "foo should no longer be used"
29
+ # end
30
+ def assert_deprecated(match = nil, deprecator = nil, &block)
31
+ match, deprecator = nil, match if match.is_a?(ActiveSupport::Deprecation)
32
+
33
+ unless deprecator
34
+ raise ArgumentError, "No deprecator given"
35
+ end
36
+
37
+ result, warnings = collect_deprecations(deprecator, &block)
38
+ assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
39
+ if match
40
+ match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
41
+ assert warnings.any? { |w| match.match?(w) }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
42
+ end
43
+ result
44
+ end
45
+
46
+ # Asserts that no deprecation warnings are emitted by the given deprecator during the execution of the yielded block.
47
+ #
48
+ # assert_not_deprecated(CustomDeprecator) do
49
+ # CustomDeprecator.warn "message" # fails assertion
50
+ # end
51
+ #
52
+ # assert_not_deprecated(ActiveSupport::Deprecation.new) do
53
+ # CustomDeprecator.warn "message" # passes assertion, different deprecator
54
+ # end
55
+ def assert_not_deprecated(deprecator, &block)
56
+ result, deprecations = collect_deprecations(deprecator, &block)
57
+ assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
58
+ result
59
+ end
60
+
61
+ # Returns the return value of the block and an array of all the deprecation warnings emitted by the given
62
+ # +deprecator+ during the execution of the yielded block.
63
+ #
64
+ # collect_deprecations(CustomDeprecator) do
65
+ # CustomDeprecator.warn "message"
66
+ # ActiveSupport::Deprecation.new.warn "other message"
67
+ # :result
68
+ # end # => [:result, ["message"]]
69
+ def collect_deprecations(deprecator)
70
+ old_behavior = deprecator.behavior
71
+ deprecations = []
72
+ deprecator.behavior = Proc.new do |message, callstack|
73
+ deprecations << message
74
+ end
75
+ result = yield
76
+ [result, deprecations]
77
+ ensure
78
+ deprecator.behavior = old_behavior
79
+ end
80
+ end
81
+ end
82
+ end