activesupport 6.0.0

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 (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,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module Assertions
6
+ UNTRACKED = Object.new # :nodoc:
7
+
8
+ # Asserts that an expression is not truthy. Passes if <tt>object</tt> is
9
+ # +nil+ or +false+. "Truthy" means "considered true in a conditional"
10
+ # like <tt>if foo</tt>.
11
+ #
12
+ # assert_not nil # => true
13
+ # assert_not false # => true
14
+ # assert_not 'foo' # => Expected "foo" to be nil or false
15
+ #
16
+ # An error message can be specified.
17
+ #
18
+ # assert_not foo, 'foo should be false'
19
+ def assert_not(object, message = nil)
20
+ message ||= "Expected #{mu_pp(object)} to be nil or false"
21
+ assert !object, message
22
+ end
23
+
24
+ # Assertion that the block should not raise an exception.
25
+ #
26
+ # Passes if evaluated code in the yielded block raises no exception.
27
+ #
28
+ # assert_nothing_raised do
29
+ # perform_service(param: 'no_exception')
30
+ # end
31
+ def assert_nothing_raised
32
+ yield
33
+ end
34
+
35
+ # Test numeric difference between the return value of an expression as a
36
+ # result of what is evaluated in the yielded block.
37
+ #
38
+ # assert_difference 'Article.count' do
39
+ # post :create, params: { article: {...} }
40
+ # end
41
+ #
42
+ # An arbitrary expression is passed in and evaluated.
43
+ #
44
+ # assert_difference 'Article.last.comments(:reload).size' do
45
+ # post :create, params: { comment: {...} }
46
+ # end
47
+ #
48
+ # An arbitrary positive or negative difference can be specified.
49
+ # The default is <tt>1</tt>.
50
+ #
51
+ # assert_difference 'Article.count', -1 do
52
+ # post :delete, params: { id: ... }
53
+ # end
54
+ #
55
+ # An array of expressions can also be passed in and evaluated.
56
+ #
57
+ # assert_difference [ 'Article.count', 'Post.count' ], 2 do
58
+ # post :create, params: { article: {...} }
59
+ # end
60
+ #
61
+ # A hash of expressions/numeric differences can also be passed in and evaluated.
62
+ #
63
+ # assert_difference ->{ Article.count } => 1, ->{ Notification.count } => 2 do
64
+ # post :create, params: { article: {...} }
65
+ # end
66
+ #
67
+ # A lambda or a list of lambdas can be passed in and evaluated:
68
+ #
69
+ # assert_difference ->{ Article.count }, 2 do
70
+ # post :create, params: { article: {...} }
71
+ # end
72
+ #
73
+ # assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
74
+ # post :create, params: { article: {...} }
75
+ # end
76
+ #
77
+ # An error message can be specified.
78
+ #
79
+ # assert_difference 'Article.count', -1, 'An Article should be destroyed' do
80
+ # post :delete, params: { id: ... }
81
+ # end
82
+ def assert_difference(expression, *args, &block)
83
+ expressions =
84
+ if expression.is_a?(Hash)
85
+ message = args[0]
86
+ expression
87
+ else
88
+ difference = args[0] || 1
89
+ message = args[1]
90
+ Hash[Array(expression).map { |e| [e, difference] }]
91
+ end
92
+
93
+ exps = expressions.keys.map { |e|
94
+ e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
95
+ }
96
+ before = exps.map(&:call)
97
+
98
+ retval = yield
99
+
100
+ expressions.zip(exps, before) do |(code, diff), exp, before_value|
101
+ error = "#{code.inspect} didn't change by #{diff}"
102
+ error = "#{message}.\n#{error}" if message
103
+ assert_equal(before_value + diff, exp.call, error)
104
+ end
105
+
106
+ retval
107
+ end
108
+
109
+ # Assertion that the numeric result of evaluating an expression is not
110
+ # changed before and after invoking the passed in block.
111
+ #
112
+ # assert_no_difference 'Article.count' do
113
+ # post :create, params: { article: invalid_attributes }
114
+ # end
115
+ #
116
+ # A lambda can be passed in and evaluated.
117
+ #
118
+ # assert_no_difference -> { Article.count } do
119
+ # post :create, params: { article: invalid_attributes }
120
+ # end
121
+ #
122
+ # An error message can be specified.
123
+ #
124
+ # assert_no_difference 'Article.count', 'An Article should not be created' do
125
+ # post :create, params: { article: invalid_attributes }
126
+ # end
127
+ #
128
+ # An array of expressions can also be passed in and evaluated.
129
+ #
130
+ # assert_no_difference [ 'Article.count', -> { Post.count } ] do
131
+ # post :create, params: { article: invalid_attributes }
132
+ # end
133
+ def assert_no_difference(expression, message = nil, &block)
134
+ assert_difference expression, 0, message, &block
135
+ end
136
+
137
+ # Assertion that the result of evaluating an expression is changed before
138
+ # and after invoking the passed in block.
139
+ #
140
+ # assert_changes 'Status.all_good?' do
141
+ # post :create, params: { status: { ok: false } }
142
+ # end
143
+ #
144
+ # You can pass the block as a string to be evaluated in the context of
145
+ # the block. A lambda can be passed for the block as well.
146
+ #
147
+ # assert_changes -> { Status.all_good? } do
148
+ # post :create, params: { status: { ok: false } }
149
+ # end
150
+ #
151
+ # The assertion is useful to test side effects. The passed block can be
152
+ # anything that can be converted to string with #to_s.
153
+ #
154
+ # assert_changes :@object do
155
+ # @object = 42
156
+ # end
157
+ #
158
+ # The keyword arguments :from and :to can be given to specify the
159
+ # expected initial value and the expected value after the block was
160
+ # executed.
161
+ #
162
+ # assert_changes :@object, from: nil, to: :foo do
163
+ # @object = :foo
164
+ # end
165
+ #
166
+ # An error message can be specified.
167
+ #
168
+ # assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do
169
+ # post :create, params: { status: { incident: true } }
170
+ # end
171
+ def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block)
172
+ exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
173
+
174
+ before = exp.call
175
+ retval = yield
176
+
177
+ unless from == UNTRACKED
178
+ error = "#{expression.inspect} isn't #{from.inspect}"
179
+ error = "#{message}.\n#{error}" if message
180
+ assert from === before, error
181
+ end
182
+
183
+ after = exp.call
184
+
185
+ error = "#{expression.inspect} didn't change"
186
+ error = "#{error}. It was already #{to}" if before == to
187
+ error = "#{message}.\n#{error}" if message
188
+ assert before != after, error
189
+
190
+ unless to == UNTRACKED
191
+ error = "#{expression.inspect} didn't change to as expected\n"
192
+ error = "#{error}Expected: #{to.inspect}\n"
193
+ error = "#{error} Actual: #{after.inspect}"
194
+ error = "#{message}.\n#{error}" if message
195
+ assert to === after, error
196
+ end
197
+
198
+ retval
199
+ end
200
+
201
+ # Assertion that the result of evaluating an expression is not changed before
202
+ # and after invoking the passed in block.
203
+ #
204
+ # assert_no_changes 'Status.all_good?' do
205
+ # post :create, params: { status: { ok: true } }
206
+ # end
207
+ #
208
+ # An error message can be specified.
209
+ #
210
+ # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
211
+ # post :create, params: { status: { ok: false } }
212
+ # end
213
+ def assert_no_changes(expression, message = nil, &block)
214
+ exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
215
+
216
+ before = exp.call
217
+ retval = yield
218
+ after = exp.call
219
+
220
+ error = "#{expression.inspect} did change to #{after}"
221
+ error = "#{message}.\n#{error}" if message
222
+ assert before == after, error
223
+
224
+ retval
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem "minitest"
4
+
5
+ require "minitest"
6
+
7
+ 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,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,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deprecation"
4
+
5
+ module ActiveSupport
6
+ module Testing
7
+ module Deprecation #:nodoc:
8
+ def assert_deprecated(match = nil, deprecator = nil, &block)
9
+ result, warnings = collect_deprecations(deprecator, &block)
10
+ assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
11
+ if match
12
+ match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
13
+ assert warnings.any? { |w| match.match?(w) }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
14
+ end
15
+ result
16
+ end
17
+
18
+ def assert_not_deprecated(deprecator = nil, &block)
19
+ result, deprecations = collect_deprecations(deprecator, &block)
20
+ assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
21
+ result
22
+ end
23
+
24
+ def collect_deprecations(deprecator = nil)
25
+ deprecator ||= ActiveSupport::Deprecation
26
+ old_behavior = deprecator.behavior
27
+ deprecations = []
28
+ deprecator.behavior = Proc.new do |message, callstack|
29
+ deprecations << message
30
+ end
31
+ result = yield
32
+ [result, deprecations]
33
+ ensure
34
+ deprecator.behavior = old_behavior
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module ActiveSupport
6
+ module Testing
7
+ # Adds simple access to sample files called file fixtures.
8
+ # File fixtures are normal files stored in
9
+ # <tt>ActiveSupport::TestCase.file_fixture_path</tt>.
10
+ #
11
+ # File fixtures are represented as +Pathname+ objects.
12
+ # This makes it easy to extract specific information:
13
+ #
14
+ # file_fixture("example.txt").read # get the file's content
15
+ # file_fixture("example.mp3").size # get the file size
16
+ module FileFixtures
17
+ extend ActiveSupport::Concern
18
+
19
+ included do
20
+ class_attribute :file_fixture_path, instance_writer: false
21
+ end
22
+
23
+ # Returns a +Pathname+ to the fixture file named +fixture_name+.
24
+ #
25
+ # Raises +ArgumentError+ if +fixture_name+ can't be found.
26
+ def file_fixture(fixture_name)
27
+ path = Pathname.new(File.join(file_fixture_path, fixture_name))
28
+
29
+ if path.exist?
30
+ path
31
+ else
32
+ msg = "the directory '%s' does not contain a file named '%s'"
33
+ raise ArgumentError, msg % [file_fixture_path, fixture_name]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module Isolation
6
+ require "thread"
7
+
8
+ def self.included(klass) #:nodoc:
9
+ klass.class_eval do
10
+ parallelize_me!
11
+ end
12
+ end
13
+
14
+ def self.forking_env?
15
+ !ENV["NO_FORK"] && Process.respond_to?(:fork)
16
+ end
17
+
18
+ def run
19
+ serialized = run_in_isolation do
20
+ super
21
+ end
22
+
23
+ Marshal.load(serialized)
24
+ end
25
+
26
+ module Forking
27
+ def run_in_isolation(&blk)
28
+ read, write = IO.pipe
29
+ read.binmode
30
+ write.binmode
31
+
32
+ pid = fork do
33
+ read.close
34
+ yield
35
+ begin
36
+ if error?
37
+ failures.map! { |e|
38
+ begin
39
+ Marshal.dump e
40
+ e
41
+ rescue TypeError
42
+ ex = Exception.new e.message
43
+ ex.set_backtrace e.backtrace
44
+ Minitest::UnexpectedError.new ex
45
+ end
46
+ }
47
+ end
48
+ test_result = defined?(Minitest::Result) ? Minitest::Result.from(self) : dup
49
+ result = Marshal.dump(test_result)
50
+ end
51
+
52
+ write.puts [result].pack("m")
53
+ exit!
54
+ end
55
+
56
+ write.close
57
+ result = read.read
58
+ Process.wait2(pid)
59
+ result.unpack1("m")
60
+ end
61
+ end
62
+
63
+ module Subprocess
64
+ ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
65
+
66
+ # Crazy H4X to get this working in windows / jruby with
67
+ # no forking.
68
+ def run_in_isolation(&blk)
69
+ require "tempfile"
70
+
71
+ if ENV["ISOLATION_TEST"]
72
+ yield
73
+ test_result = defined?(Minitest::Result) ? Minitest::Result.from(self) : dup
74
+ File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
75
+ file.puts [Marshal.dump(test_result)].pack("m")
76
+ end
77
+ exit!
78
+ else
79
+ Tempfile.open("isolation") do |tmpfile|
80
+ env = {
81
+ "ISOLATION_TEST" => self.class.name,
82
+ "ISOLATION_OUTPUT" => tmpfile.path
83
+ }
84
+
85
+ test_opts = "-n#{self.class.name}##{name}"
86
+
87
+ load_path_args = []
88
+ $-I.each do |p|
89
+ load_path_args << "-I"
90
+ load_path_args << File.expand_path(p)
91
+ end
92
+
93
+ child = IO.popen([env, Gem.ruby, *load_path_args, $0, *ORIG_ARGV, test_opts])
94
+
95
+ begin
96
+ Process.wait(child.pid)
97
+ rescue Errno::ECHILD # The child process may exit before we wait
98
+ nil
99
+ end
100
+
101
+ return tmpfile.read.unpack1("m")
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ include forking_env? ? Forking : Subprocess
108
+ end
109
+ end
110
+ end