lib/minitest_to_rspec/input/model/klass.rb
# frozen_string_literal: true
require 'minitest_to_rspec/input/model/base'
module MinitestToRspec
module Input
module Model
# Data object. Represents a `:class` S-expression.
class Klass < Base
def initialize(exp)
assert_sexp_type(:class, exp)
@exp = exp.dup
assert_valid_name
end
def action_controller_test_case?
lineage?(parent, %i[ActionController TestCase])
end
def action_mailer_test_case?
lineage?(parent, %i[ActionMailer TestCase])
end
def active_support_test_case?
lineage?(parent, %i[ActiveSupport TestCase])
end
# Raise an error if we don't know now to process the name
# of this class. Specifically, classes with module-shorthand.
def assert_valid_name
if name.is_a?(Symbol)
# Valid
elsif name.respond_to?(:sexp_type) && name.sexp_type == :colon2
raise ModuleShorthandError
else
raise ProcessingError, "Unexpected class expression: #{name}"
end
end
def block?
!block.empty?
end
def block
@_block ||= @exp[3..-1] || []
end
def test_unit_test_case?
lineage?(parent, %i[Test Unit TestCase])
end
def draper_test_case?
lineage?(parent, %i[Draper TestCase])
end
# Returns the name of the class. Examples:
#
# - Banana #=> :Banana
# - Fruit::Banana #=> s(:colon2, s(:const, :Fruit), :Banana)
#
# Note that the latter (module shorthand) is not supported
# by MinitestToRspec. See `#assert_valid_name`.
#
def name
@exp[1]
end
# Returns the "inheritance". Examples:
#
# - Inherit nothing #=> nil
# - Inherit Foo #=> s(:const, :Foo)
# - Inherit Bar::Foo #=> s(:colon2, s(:const, :Bar), :Foo)
#
def parent
@_parent ||= @exp[2]
end
# Returns true if `@exp` inherits from, e.g. ActiveSupport::TestCase.
# TODO: Other test case parent classes.
def test_case?
return false unless sexp_type?(:colon2, parent)
active_support_test_case? ||
action_controller_test_case? ||
action_mailer_test_case? ||
test_unit_test_case? ||
draper_test_case?
end
private
def ancestor_names(exp)
return [exp] if exp.is_a?(Symbol)
sexp_type?(:colon2, exp) || sexp_type?(:const, exp) ||
raise(TypeError, "Expected :const or :colon2, got #{exp.inspect}")
exp.sexp_body.flat_map { |entry| ancestor_names(entry) }
end
def lineage?(exp, names)
assert_sexp_type(:colon2, exp)
ancestor_names(exp) == names
end
end
end
end
end