lib/minitest_to_rspec/input/subprocessors/iter.rb
# frozen_string_literal: true
require 'minitest_to_rspec/input/subprocessors/base'
require 'minitest_to_rspec/input/model/iter'
module MinitestToRspec
module Input
module Subprocessors
# Processes `s(:iter, ..)` expressions.
class Iter < Base
def initialize(sexp, rails, mocha)
super(rails, mocha)
@exp = Model::Iter.new(sexp)
sexp.clear
end
def process
process_exp(@exp)
end
private
# Returns an expression representing an RSpec `change {}`
# matcher. See also `change_by` below.
def change(exp)
matcher_with_block(:change, exp)
end
# Returns an expression representing an RSpec `change {}.by()` matcher.
def change_by(diff_exp, by_exp)
s(:call,
change(diff_exp),
:by,
by_exp
)
end
def matcher_with_block(matcher_name, block)
s(:iter,
s(:call, nil, matcher_name),
0,
block
)
end
def method_assert_difference(exp)
call = exp[1]
block = exp[3]
by = call[4]
what = parse(call[3][1])
matcher = by.nil? ? change(what) : change_by(what, by)
expect_to(matcher, block, false)
end
def method_assert_no_difference(exp)
call = exp[1]
block = exp[3]
what = parse(call[3][1])
expect_to_not(change(what), block, false)
end
def method_assert_nothing_raised(exp)
block = exp[3]
expect_to_not(raise_error, block, false)
end
def method_assert_raise(iter)
method_assert_raises(iter)
end
def method_assert_raises(iter)
expect_to(raise_error(*iter.call_arguments), iter.block, false)
end
def method_refute_raise(iter)
method_refute_raises(iter)
end
def method_refute_raises(iter)
expect_to_not(raise_error(*iter.call_arguments), iter.block, false)
end
def method_setup(exp)
replace_method_name(exp, :before)
end
def method_teardown(exp)
replace_method_name(exp, :after)
end
def name_of_processing_method(iter)
method_name = iter[1][2]
"method_#{method_name}".to_sym
end
def parse(str)
RubyParser.new.parse(str)
end
# Given a `Model::Iter`, returns a `Sexp`
def process_exp(exp)
if processable?(exp)
send_to_processing_method(exp)
else
process_uninteresting_iter(exp.sexp)
end
end
def processable?(iter)
if !iter.empty? && iter[1].sexp_type == :call
method_name = iter[1][2]
decision = "#{method_name}?".to_sym
iter.respond_to?(decision) && iter.public_send(decision)
else
false
end
end
def process_uninteresting_iter(exp)
iter = s(exp.shift)
until exp.empty?
iter << full_process(exp.shift)
end
iter
end
# Given `args` which came from an `assert_raise` or an
# `assert_raises`, return a `raise_error` matcher.
# When the last argument is a string, it represents the
# assertion failure message, and is discarded.
def raise_error(*args)
args.pop if !args.empty? && args.last.sexp_type == :str
matcher(:raise_error, *args)
end
def replace_method_name(exp, new_method)
iter = s(:iter, s(:call, nil, new_method))
exp.each do |e| iter << full_process(e) end
iter
end
def send_to_processing_method(exp)
send(name_of_processing_method(exp), exp)
end
end
end
end
end