rails/activesupport/test/deprecation_test.rb
Rafael Mendonça França fc2dc7c8d3
Remove deprecated support to call the following methods without passing a deprecator
- `deprecate`
  - `deprecate_constant`
  - `ActiveSupport::Deprecation::DeprecatedObjectProxy.new`
  - `ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new`
  - `ActiveSupport::Deprecation::DeprecatedConstantProxy.new`
  - `assert_deprecated`
  - `assert_not_deprecated`
  - `collect_deprecations`
2024-05-01 18:45:45 +00:00

932 lines
28 KiB
Ruby

# frozen_string_literal: true
require_relative "abstract_unit"
require "logger"
require "stringio"
require "active_support/core_ext/enumerable"
require "active_support/testing/stream"
class Deprecatee
attr_accessor :fubar, :foo_bar
def zero() 0 end
def one(a) a end
def multi(a, b, c) [a, b, c] end
end
module Undeprecated
module Foo
BAR = "foo bar"
end
class Error < StandardError; end
end
class DeprecationTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Stream
def setup
@deprecator = ActiveSupport::Deprecation.new
end
test "assert_deprecated" do
assert_deprecated(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
assert_deprecated(@deprecator) do
@deprecator.warn("whatever")
end
end
test "passing callstack as `caller` is deprecated" do
assert_deprecated(/Passing the result of `caller` to ActiveSupport::Deprecation#warn/, ActiveSupport.deprecator) do
assert_deprecated(@deprecator) do
@deprecator.warn("Yo dawg!", caller)
end
end
end
test "assert_deprecated requires a deprecator" do
assert_raises(ArgumentError) do
assert_deprecated do
ActiveSupport::Deprecation._instance.warn
end
end
end
test "assert_not_deprecated" do
assert_not_deprecated(@deprecator) do
1 + 1
end
end
test "assert_not_deprecated requires a deprecator" do
assert_raises(ArgumentError) do
assert_not_deprecated { }
end
end
test "collect_deprecations returns the return value of the block and the deprecations collected" do
result = collect_deprecations(@deprecator) do
@deprecator.warn
:result
end
assert_equal 2, result.size
assert_equal :result, result.first
assert_match "DEPRECATION WARNING:", result.last.sole
end
test "collect_deprecations requires a deprecator" do
assert_raises(ArgumentError) do
collect_deprecations { }
end
end
test "Module::deprecate" do
klass = Class.new(Deprecatee)
klass.deprecate :zero, :one, :multi, deprecator: @deprecator
assert_deprecated(/zero is deprecated/, @deprecator) do
assert_equal 0, klass.new.zero
end
assert_deprecated(/one is deprecated/, @deprecator) do
assert_equal 1, klass.new.one(1)
end
assert_deprecated(/multi is deprecated/, @deprecator) do
assert_equal [1, 2, 3], klass.new.multi(1, 2, 3)
end
end
test "Module::deprecate does not expand Hash positional argument" do
klass = Class.new(Deprecatee)
klass.deprecate :one, :one!, deprecator: @deprecator
klass.alias_method :one!, :one
hash = { k: 1 }
assert_deprecated(/one is deprecated/, @deprecator) do
assert_same hash, klass.new.one(hash)
end
assert_deprecated(/one! is deprecated/, @deprecator) do
assert_same hash, klass.new.one!(hash)
end
end
test "Module::deprecate requires a deprecator" do
klass = Class.new(Deprecatee)
assert_raises(ArgumentError) do
klass.deprecate :zero
end
end
test "DeprecatedObjectProxy" do
deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, ":bomb:", @deprecator)
assert_deprecated(/:bomb:/, @deprecator) { deprecated_object.to_s }
end
test "DeprecatedObjectProxy requires a deprecator" do
assert_raises(ArgumentError) do
ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, ":bomb:")
end
end
test "nil behavior is ignored" do
@deprecator.behavior = nil
assert_deprecated("fubar", @deprecator) { @deprecator.warn("fubar") }
end
test "behavior callbacks" do
assert_callbacks_called_with(deprecator: @deprecator, message: /fubar/) do |callbacks|
@deprecator.behavior = callbacks
@deprecator.warn("fubar")
end
end
test "behavior callbacks with callable objects" do
assert_callbacks_called_with(deprecator: @deprecator, message: /fubar/) do |callbacks|
callbacks.select!(&:lambda?)
assert_not_empty callbacks
@deprecator.behavior = callbacks.map do |callback|
Object.new.tap { |object| object.define_singleton_method(:call, &callback) }
end
@deprecator.warn("fubar")
end
end
test ":raise behavior" do
@deprecator.behavior = :raise
message = "Revise this deprecated stuff now!"
callstack = caller_locations
e = assert_raise ActiveSupport::DeprecationException do
@deprecator.behavior.first.call(message, callstack, @deprecator)
end
assert_equal message, e.message
assert_equal callstack.map(&:to_s), e.backtrace.map(&:to_s)
end
test ":stderr behavior" do
@deprecator.behavior = :stderr
behavior = @deprecator.behavior.first
output = capture(:stderr) do
behavior.call("Some error!", ["call stack!"], @deprecator)
end
assert_match "Some error!", output
assert_no_match "call stack!", output
end
test ":stderr behavior with debug" do
@deprecator.behavior = :stderr
behavior = @deprecator.behavior.first
@deprecator.debug = true
output = capture(:stderr) do
behavior.call("Some error!", ["call stack!"], @deprecator)
end
assert_match "Some error!", output
assert_match "call stack!", output
end
test ":stderr behavior with #warn" do
@deprecator.behavior = :stderr
output = capture(:stderr) do
@deprecator.warn("Instance error!", ["instance call stack!"])
end
assert_match(/Instance error!/, output)
assert_match(/instance call stack!/, output)
end
test ":log behavior" do
@deprecator.behavior = :log
output = StringIO.new
with_rails_logger(Logger.new(output)) do
@deprecator.behavior.first.call("fubar", ["call stack!"], @deprecator)
end
assert_match "fubar", output.string
assert_no_match "call stack!", output.string
end
test ":log behavior with debug" do
@deprecator.behavior = :log
@deprecator.debug = true
output = StringIO.new
with_rails_logger(Logger.new(output)) do
@deprecator.behavior.first.call("fubar", ["call stack!"], @deprecator)
end
assert_match "fubar", output.string
assert_match "call stack!", output.string
end
test ":log behavior without Rails.logger" do
@deprecator.behavior = :log
output = capture(:stderr) do
with_rails_logger(nil) do
@deprecator.behavior.first.call("fubar", ["call stack!"], @deprecator)
end
end
assert_match "fubar", output
end
test ":silence behavior" do
@deprecator.behavior = :silence
behavior = @deprecator.behavior.first
output = capture(:stderr) do
behavior.call("Some error!", ["call stack!"], @deprecator)
end
assert_empty output
end
test ":notify behavior" do
@deprecator = ActiveSupport::Deprecation.new("horizon", "MyGem::Custom")
@deprecator.behavior = :notify
behavior = @deprecator.behavior.first
begin
events = []
ActiveSupport::Notifications.subscribe("deprecation.my_gem_custom") { |*args|
events << args.extract_options!
}
behavior.call("Some error!", ["call stack!"], @deprecator)
assert_equal 1, events.size
assert_equal "Some error!", events.first[:message]
assert_equal ["call stack!"], events.first[:callstack]
assert_equal "horizon", events.first[:deprecation_horizon]
assert_equal "MyGem::Custom", events.first[:gem_name]
ensure
ActiveSupport::Notifications.unsubscribe("deprecation.my_gem_custom")
end
end
test ":report_error behavior" do
@deprecator = ActiveSupport::Deprecation.new("horizon", "MyGem::Custom")
@deprecator.behavior = :report
report = assert_error_reported(ActiveSupport::DeprecationException) do
@deprecator.warn
end
assert_equal true, report.handled
assert_equal :warning, report.severity
assert_equal "application", report.source
end
test "invalid behavior" do
e = assert_raises(ArgumentError) do
@deprecator.behavior = :invalid
end
assert_equal ":invalid is not a valid deprecation behavior.", e.message
end
test "DeprecatedInstanceVariableProxy" do
instance = Deprecatee.new
instance.fubar = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(instance, :foo_bar, "@fubar", deprecator: @deprecator)
instance.foo_bar = "foo bar!"
fubar_size = assert_deprecated("@fubar.size", @deprecator) { instance.fubar.size }
assert_equal instance.foo_bar.size, fubar_size
fubar_s = assert_deprecated("@fubar.to_s", @deprecator) { instance.fubar.to_s }
assert_equal instance.foo_bar.to_s, fubar_s
end
test "DeprecatedInstanceVariableProxy does not warn on inspect" do
instance = Deprecatee.new
instance.fubar = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(instance, :foo_bar, "@fubar", deprecator: @deprecator)
instance.foo_bar = "foo bar!"
fubar_inspected = assert_not_deprecated(@deprecator) { instance.fubar.inspect }
assert_equal instance.foo_bar.inspect, fubar_inspected
end
test "DeprecatedInstanceVariableProxy requires a deprecator" do
assert_raises(ArgumentError) do
ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(Deprecatee.new, :foobar, "@fubar")
end
end
test "DeprecatedConstantProxy" do
proxy = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("FUBAR", "Undeprecated::Foo::BAR", @deprecator)
assert_deprecated("FUBAR", @deprecator) do
assert_equal Undeprecated::Foo::BAR, proxy
end
end
test "DeprecatedConstantProxy does not warn on .class" do
proxy = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("FUBAR", "Undeprecated::Foo::BAR", @deprecator)
fubar_class = assert_not_deprecated(@deprecator) { proxy.class }
assert_equal Undeprecated::Foo::BAR.class, fubar_class
end
test "DeprecatedConstantProxy with child constant" do
proxy = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Fuu", "Undeprecated::Foo", @deprecator)
assert_deprecated("Fuu", @deprecator) do
assert_equal Undeprecated::Foo::BAR, proxy::BAR
end
assert_deprecated("Fuu", @deprecator) do
assert_raises(NameError) { proxy::DOES_NOT_EXIST }
end
end
test "DeprecatedConstantProxy requires a deprecator" do
assert_raise(ArgumentError) do
ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Fuu", "Undeprecated::Foo")
end
end
test "deprecate_constant" do
legacy = Module.new { def self.name; "Legacy"; end }
legacy.include ActiveSupport::Deprecation::DeprecatedConstantAccessor
legacy.deprecate_constant "FUBAR", "Undeprecated::Foo::BAR", deprecator: @deprecator
assert_deprecated("Legacy::FUBAR", @deprecator) do
assert_equal Undeprecated::Foo::BAR, legacy::FUBAR
end
end
test "deprecate_constant when rescuing a deprecated error" do
legacy = Module.new { def self.name; "Legacy"; end }
legacy.include ActiveSupport::Deprecation::DeprecatedConstantAccessor
legacy.deprecate_constant "Error", "Undeprecated::Error", deprecator: @deprecator
assert_deprecated("Legacy::Error", @deprecator) do
assert_nothing_raised do
raise Undeprecated::Error
rescue legacy::Error
end
end
end
test "deprecate_constant requires a deprecator" do
legacy = Module.new.include(ActiveSupport::Deprecation::DeprecatedConstantAccessor)
assert_raises(ArgumentError) do
legacy.deprecate_constant "OLD", "NEW"
end
end
test "assert_deprecated raises when no deprecation warning" do
assert_raises(Minitest::Assertion) do
assert_deprecated(@deprecator) { 1 + 1 }
end
end
test "assert_not_deprecated raises when some deprecation warning" do
assert_raises(Minitest::Assertion) do
assert_not_deprecated(@deprecator) { @deprecator.warn }
end
end
test "assert_deprecated without match argument" do
assert_deprecated(@deprecator) do
@deprecator.warn
end
end
test "assert_deprecated matches any warning from block" do
assert_deprecated("abc", @deprecator) do
@deprecator.warn "abc"
@deprecator.warn "def"
end
rescue Minitest::Assertion
flunk "assert_deprecated should match any warning in block, not just the last one"
end
test "assert_not_deprecated returns the result of the block" do
assert_equal 123, assert_not_deprecated(@deprecator) { 123 }
end
test "assert_deprecated returns the result of the block" do
result = assert_deprecated("abc", @deprecator) do
@deprecator.warn "abc"
123
end
assert_equal 123, result
end
test "silence" do
assert_not @deprecator.silenced
@deprecator.silence do
assert_not_deprecated(@deprecator) { @deprecator.warn }
end
assert_deprecated(@deprecator) { @deprecator.warn }
@deprecator.silenced = true
assert @deprecator.silenced
assert_not_deprecated(@deprecator) { @deprecator.warn }
end
test "silence returns the result of the block" do
assert_equal 123, @deprecator.silence { 123 }
end
test "silence ensures silencing is reverted after an error is raised" do
assert_raises do
@deprecator.silence { raise }
end
assert_deprecated(@deprecator) { @deprecator.warn }
end
test "silence only affects the current thread" do
@deprecator.silence do
assert_not_deprecated(@deprecator) { @deprecator.warn }
Thread.new do
assert_deprecated(@deprecator) { @deprecator.warn }
@deprecator.silence do
assert_not_deprecated(@deprecator) { @deprecator.warn }
end
assert_deprecated(@deprecator) { @deprecator.warn }
end.join
assert_not_deprecated(@deprecator) { @deprecator.warn }
end
end
test "Module::deprecate with method name only" do
klass = Class.new(Deprecatee)
klass.deprecate :fubar, :fubar=, deprecator: @deprecator
assert_deprecated(@deprecator) { klass.new.fubar }
assert_deprecated(@deprecator) { klass.new.fubar = :foo }
end
test "Module::deprecate with alternative method" do
klass = Class.new(Deprecatee)
klass.deprecate fubar: :foo_bar, deprecator: @deprecator
assert_deprecated(/use foo_bar instead/, @deprecator) { klass.new.fubar }
end
test "Module::deprecate with message" do
klass = Class.new(Deprecatee)
klass.deprecate fubar: "this is the old way", deprecator: @deprecator
assert_deprecated(/this is the old way/, @deprecator) { klass.new.fubar }
end
test "overriding deprecated_method_warning" do
deprecator = deprecator_with_messages
class << deprecator
private
def deprecated_method_warning(method, message)
"deprecator.deprecated_method_warning.#{method}"
end
end
deprecatee = Class.new do
def method
end
deprecate :method, deprecator: deprecator
end
deprecatee.new.method
assert deprecator.messages.first.match("DEPRECATION WARNING: deprecator.deprecated_method_warning.method")
end
test "Module::deprecate with custom deprecator" do
custom_deprecator = Struct.new(:deprecation_warning).new
assert_called_with(custom_deprecator, :deprecation_warning, [:method, nil]) do
klass = Class.new do
def method
end
deprecate :method, deprecator: custom_deprecator
end
klass.new.method
end
end
test "DeprecatedConstantProxy with explicit deprecator" do
deprecator = deprecator_with_messages
klass = Class.new
klass.const_set(:OLD, ActiveSupport::Deprecation::DeprecatedConstantProxy.new("klass::OLD", "Object", deprecator))
assert_difference("deprecator.messages.size") do
klass::OLD.to_s
end
end
test "DeprecatedConstantProxy with message" do
deprecator = deprecator_with_messages
klass = Class.new
klass.const_set(:OLD, ActiveSupport::Deprecation::DeprecatedConstantProxy.new("klass::OLD", "Object", deprecator, message: "foo"))
klass::OLD.to_s
assert_match "foo", deprecator.messages.last
end
test "default deprecation_horizon is greater than the current Rails version" do
assert_operator ActiveSupport::Deprecation.new.deprecation_horizon, :>, ActiveSupport::VERSION::STRING
end
test "default gem_name is Rails" do
deprecator = ActiveSupport::Deprecation.new
deprecator.send(:deprecated_method_warning, :deprecated_method, "You are calling deprecated method").tap do |message|
assert_match(/is deprecated and will be removed from Rails/, message)
end
end
test "custom gem_name" do
deprecator = ActiveSupport::Deprecation.new("2.0", "Custom")
deprecator.send(:deprecated_method_warning, :deprecated_method, "You are calling deprecated method").tap do |message|
assert_match(/is deprecated and will be removed from Custom/, message)
end
end
test "Module::deprecate can be called before the target method is defined" do
klass = Class.new(Deprecatee)
klass.deprecate :multi!, deprecator: @deprecator
klass.alias_method :multi!, :multi
assert_deprecated(/multi! is deprecated/, @deprecator) do
assert_equal [1, 2, 3], klass.new.multi!(1, 2, 3)
end
end
test "warn with empty callstack" do
@deprecator.behavior = :silence
assert_nothing_raised do
@deprecator.warn("message", [])
Thread.new { @deprecator.warn("message") }.join
end
end
test "disallowed_warnings is empty by default" do
assert_equal [], @deprecator.disallowed_warnings
end
test "disallowed_warnings can be configured" do
config_warnings = ["unsafe_method is going away"]
@deprecator.disallowed_warnings = config_warnings
assert_equal @deprecator.disallowed_warnings, config_warnings
end
test "disallowed_behavior does not trigger when disallowed_warnings is empty" do
@deprecator.disallowed_behavior = proc { flunk }
assert_deprecated(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
end
test "disallowed_behavior does not trigger when disallowed_warnings does not match the warning" do
@deprecator.disallowed_behavior = proc { flunk }
@deprecator.disallowed_warnings = ["foo bar"]
assert_deprecated(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
end
test "disallowed_warnings can match using a substring" do
@deprecator.disallowed_warnings = ["fubar"]
assert_disallowed(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
end
test "disallowed_warnings can match using a substring as a symbol" do
@deprecator.disallowed_warnings = [:fubar]
assert_disallowed(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
end
test "disallowed_warnings can match using a regexp" do
@deprecator.disallowed_warnings = [/f[aeiou]+bar/]
assert_disallowed(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
end
test "disallowed_warnings matches all warnings when set to :all" do
@deprecator.disallowed_warnings = :all
assert_disallowed(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
end
test "different behaviors for allowed and disallowed warnings" do
@deprecator.disallowed_warnings = :all
@deprecator.behavior = proc { flunk }
assert_disallowed(/fubar/, @deprecator) do
@deprecator.warn("using fubar is deprecated")
end
end
test "disallowed_warnings with the default warning message" do
@deprecator.disallowed_warnings = :all
assert_disallowed(@deprecator) { @deprecator.warn }
@deprecator.disallowed_warnings = ["fubar"]
assert_deprecated(@deprecator) { @deprecator.warn }
end
test "disallowed_behavior callbacks" do
assert_callbacks_called_with(deprecator: @deprecator, message: /fubar/) do |callbacks|
@deprecator.disallowed_behavior = callbacks
@deprecator.disallowed_warnings = ["fubar"]
@deprecator.warn("fubar")
end
end
test "allow" do
@deprecator.disallowed_warnings = :all
assert_disallowed(@deprecator) { @deprecator.warn }
@deprecator.allow do
assert_deprecated(@deprecator) { @deprecator.warn }
end
end
test "allow only allows matching warnings using a substring" do
@deprecator.disallowed_warnings = :all
@deprecator.allow(["foo bar", "baz qux"]) do
assert_deprecated(/foo bar/, @deprecator) { @deprecator.warn("foo bar") }
assert_deprecated(/baz qux/, @deprecator) { @deprecator.warn("baz qux") }
assert_disallowed(/fubar/, @deprecator) { @deprecator.warn("fubar") }
end
end
test "allow only allows matching warnings using a substring as a symbol" do
@deprecator.disallowed_warnings = :all
@deprecator.allow([:"foo bar", :"baz qux"]) do
assert_deprecated(/foo bar/, @deprecator) { @deprecator.warn("foo bar") }
assert_deprecated(/baz qux/, @deprecator) { @deprecator.warn("baz qux") }
assert_disallowed(/fubar/, @deprecator) { @deprecator.warn("fubar") }
end
end
test "allow only allows matching warnings using a regexp" do
@deprecator.disallowed_warnings = :all
@deprecator.allow([/(foo|baz) (bar|qux)/]) do
assert_deprecated(/foo bar/, @deprecator) { @deprecator.warn("foo bar") }
assert_deprecated(/baz qux/, @deprecator) { @deprecator.warn("baz qux") }
assert_disallowed(/fubar/, @deprecator) { @deprecator.warn("fubar") }
end
end
test "allow only affects its block" do
@deprecator.disallowed_warnings = :all
@deprecator.allow do
assert_deprecated(@deprecator) { @deprecator.warn }
end
assert_disallowed(@deprecator) { @deprecator.warn }
end
test "allow only affects the current thread" do
@deprecator.disallowed_warnings = :all
@deprecator.allow do
assert_deprecated(@deprecator) { @deprecator.warn }
Thread.new do
assert_disallowed(@deprecator) { @deprecator.warn }
@deprecator.allow do
assert_deprecated(@deprecator) { @deprecator.warn }
end
assert_disallowed(@deprecator) { @deprecator.warn }
end.join
assert_deprecated(@deprecator) { @deprecator.warn }
end
end
test "allow with :if option" do
@deprecator.disallowed_warnings = :all
@deprecator.allow("fubar", if: true) do
assert_deprecated(/fubar/, @deprecator) { @deprecator.warn("fubar") }
end
@deprecator.allow("fubar", if: false) do
assert_disallowed(/fubar/, @deprecator) { @deprecator.warn("fubar") }
end
end
test "allow with :if option as a proc" do
@deprecator.disallowed_warnings = :all
@deprecator.allow("fubar", if: -> { true }) do
assert_deprecated(/fubar/, @deprecator) { @deprecator.warn("fubar") }
end
@deprecator.allow("fubar", if: -> { false }) do
assert_disallowed(/fubar/, @deprecator) { @deprecator.warn("fubar") }
end
end
test "allow with the default warning message" do
@deprecator.disallowed_warnings = :all
@deprecator.allow(:all) do
assert_deprecated(@deprecator) { @deprecator.warn }
end
@deprecator.allow(["fubar"]) do
assert_disallowed(@deprecator) { @deprecator.warn }
end
end
test "warn deprecation skips the internal caller locations" do
@deprecator.behavior = ->(_, callstack, *) { @callstack = callstack }
method_that_emits_deprecation(@deprecator)
assert_equal File.expand_path(__FILE__), @callstack.first.absolute_path
assert_equal __LINE__ - 2, @callstack.first.lineno
end
class_eval(<<~RUBY, "/path/to/template.html.erb", 1)
def generated_method_that_call_deprecation(deprecator)
deprecator.warn("Here", caller_locations(0, 10))
end
RUBY
test "warn deprecation can blame code generated with eval" do
@deprecator.behavior = ->(message, *) { @message = message }
generated_method_that_call_deprecation(@deprecator)
if RUBY_VERSION >= "3.4"
assert_equal "DEPRECATION WARNING: Here (called from DeprecationTest#generated_method_that_call_deprecation at /path/to/template.html.erb:2)", @message
else
assert_equal "DEPRECATION WARNING: Here (called from generated_method_that_call_deprecation at /path/to/template.html.erb:2)", @message
end
end
test "warn deprecation can blame code from internal methods" do
@deprecator.behavior = ->(message, *) { @message = message }
method_that_emits_deprecation_with_internal_method(@deprecator)
assert_includes(@message, "/path/to/user/code.rb")
end
class_eval(<<~RUBY, "/path/to/user/code.rb", 1)
def method_that_emits_deprecation_with_internal_method(deprecator)
[1].each { deprecator.warn }
end
RUBY
private
def method_that_emits_deprecation(deprecator)
deprecator.warn
end
def with_rails_application_deprecators(&block)
application = Struct.new(:deprecators).new(ActiveSupport::Deprecation::Deprecators.new)
rails = Struct.new(:application).new(application)
rails.application.deprecators[:deprecator] = @deprecator
stub_const(Object, :Rails, rails, &block)
end
def deprecator_with_messages
klass = Class.new(ActiveSupport::Deprecation)
deprecator = klass.new
deprecator.behavior = Proc.new { |message, callstack| deprecator.messages << message }
def deprecator.messages
@messages ||= []
end
deprecator
end
module ::Rails; end
def with_rails_logger(logger)
::Rails.singleton_class.class_eval do
alias_method :__original_logger, :logger if method_defined?(:logger)
define_method(:logger) { logger }
end
yield logger
ensure
::Rails.singleton_class.class_eval do
if method_defined?(:__original_logger)
alias_method :logger, :__original_logger
undef_method :__original_logger
else
undef_method :logger
end
end
end
# a la collect_deprecations
def collect_disallowed(deprecator)
deprecator ||= ActiveSupport::Deprecation
original_disallowed_behavior = deprecator.disallowed_behavior
disallowed = []
deprecator.disallowed_behavior = proc { |message| disallowed << message }
result = yield
[result, disallowed]
ensure
deprecator.disallowed_behavior = original_disallowed_behavior
end
# a la assert_deprecated
def assert_disallowed(match = nil, deprecator = nil, &block)
match, deprecator = nil, match if match.is_a?(ActiveSupport::Deprecation)
result, disallowed = collect_disallowed(deprecator, &block)
assert_not_empty disallowed, "Expected a disallowed deprecation within the block but received none"
if match
match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
assert disallowed.any?(match), "No disallowed deprecations matched #{match}: #{disallowed.inspect}"
end
result
end
def assert_callbacks_called_with(matchers = {})
matchers[:message] ||= String
matchers[:callstack] ||= Array
matchers[:deprecator]&.tap do |deprecator|
matchers[:deprecation_horizon] ||= deprecator.deprecation_horizon
matchers[:gem_name] ||= deprecator.gem_name
end
bindings = []
callbacks = [
lambda { |message, callstack, deprecator| bindings << binding },
proc { |message, callstack, deprecator| bindings << binding },
lambda { |message, callstack, deprecation_horizon, gem_name| bindings << binding },
proc { |message, callstack, deprecation_horizon, gem_name| bindings << binding },
lambda { |message, callstack| bindings << binding },
proc { |message, callstack| bindings << binding },
proc { |message| bindings << binding },
proc { bindings << binding },
lambda do |*args|
message, callstack, deprecator = args
bindings << binding
[message, callstack, deprecator]
end,
lambda do |message, *other|
callstack, deprecator = other
bindings << binding
[callstack, deprecator]
end,
lambda do |message, callstack, *details|
deprecation_horizon, gem_name = details
bindings << binding
[deprecation_horizon, gem_name]
end,
]
yield callbacks
assert_equal callbacks.size, bindings.size
bindings.each do |bound|
matchers.each do |name, matcher|
if bound.local_variable_defined?(name)
assert_operator matcher, :===, bound.local_variable_get(name),
"Unexpected #{name} in callback defined at #{bound.source_location.join(":")}"
end
end
end
end
end