class RuboCop::Cop::Minitest::SkipEnsure


end
do_teardown
ensure
skip ‘This test is skipped.’
rescue
assert do_something
do_setup
def test_skip_is_used_in_rescue
# good
end
end
do_teardown
if condition
ensure
assert do_something
skip ‘This test is skipped.’ if condition
def test_conditional_skip
# good
end
end
do_something
ensure
assert ‘foo’.present?
begin
skip ‘This test is skipped.’
def test_skip
# good
end
do_teardown
ensure
assert do_something
skip ‘This test is skipped.’ if condition
def test_conditional_skip
# bad
end
do_something
ensure
assert ‘foo’.present?
skip ‘This test is skipped.’
def test_skip
# bad
@example
setup process.
On the other hand, it accepts ‘skip` used in `rescue` because `ensure` may be teardown process to `begin`
If conditional `skip` is used, it checks that `ensure` is also called conditionally.
Checks that `ensure` call even if `skip`. It is unexpected that `ensure` will be called when skipping test.

def find_skip(node)

def find_skip(node)
  return unless (body = node.node_parts.first)
  body.descendants.detect { |n| n.send_type? && n.receiver.nil? && n.method?(:skip) }
end

def on_ensure(node)

def on_ensure(node)
  skip = find_skip(node)
  return if skip.nil? || use_skip_in_rescue?(skip) || valid_conditional_skip?(skip, node)
  add_offense(node.loc.keyword)
end

def use_skip_in_rescue?(skip_method)

def use_skip_in_rescue?(skip_method)
  skip_method.ancestors.detect(&:rescue_type?)
end

def valid_conditional_skip?(skip_method, ensure_node)

def valid_conditional_skip?(skip_method, ensure_node)
  if_node = skip_method.ancestors.detect(&:if_type?)
  return false unless ensure_node.body.if_type?
  match_keyword = ensure_node.body.if? ? if_node.if? : if_node.unless?
  match_keyword && ensure_node.body.condition == if_node.condition
end