2012-08-14 16:45:34 -04:00
|
|
|
module Mutant
|
2012-08-15 22:10:54 -04:00
|
|
|
# Runner that allows to mutate an entire project
|
2012-08-14 16:45:34 -04:00
|
|
|
class Runner
|
2012-08-15 22:10:54 -04:00
|
|
|
include Immutable
|
|
|
|
extend MethodObject
|
2012-08-14 16:45:34 -04:00
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
attr_reader :errors
|
2012-08-14 16:45:34 -04:00
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
def fail?
|
|
|
|
!errors.empty?
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
private
|
2012-08-14 16:45:34 -04:00
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
attr_reader :reporter
|
|
|
|
private :reporter
|
2012-08-14 16:45:34 -04:00
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
def initialize(options)
|
|
|
|
@killer = options.fetch(:killer) do
|
2012-08-14 16:45:34 -04:00
|
|
|
raise ArgumentError, 'Missing :killer in options'
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
@pattern = options.fetch(:pattern) do
|
2012-08-14 16:45:34 -04:00
|
|
|
raise ArgumentError, 'Missing :pattern in options'
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
@reporter = options.fetch(:reporter, Reporter::Null)
|
2012-08-14 16:45:34 -04:00
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
@errors = []
|
2012-08-14 16:45:34 -04:00
|
|
|
|
|
|
|
run
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
def run
|
|
|
|
@subjects = subjects.each do |subject|
|
|
|
|
reporter.subject(subject)
|
|
|
|
run_subject(subject)
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
def run_subject(subject)
|
|
|
|
subject.each do |mutation|
|
|
|
|
reporter.mutation(mutation)
|
|
|
|
kill(mutation)
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
2012-08-15 22:10:54 -04:00
|
|
|
subject.reset
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
def kill(mutation)
|
|
|
|
killer = @killer.run(mutation)
|
|
|
|
reporter.killer(killer)
|
|
|
|
if killer.fail?
|
|
|
|
@errors << killer
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
# Return candiate matcher enumerator
|
|
|
|
#
|
|
|
|
# @return [Enumerable<Class<Matcher>>]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def candidate_matchers
|
|
|
|
[Matcher::Method::Singleton, Matcher::Method::Instance].each
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
# Return candidats enumerator
|
|
|
|
#
|
|
|
|
# @return [Enumerable<Object>]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def candidates
|
|
|
|
return to_enum(__method__) unless block_given?
|
|
|
|
ObjectSpace.each_object(Module) do |candidate|
|
|
|
|
yield candidate if @pattern =~ candidate.name
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
# Return matcher enumerator
|
|
|
|
#
|
|
|
|
# @return [Enumerable<Matcher>]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def matchers(&block)
|
|
|
|
return to_enum(__method__) unless block_given?
|
|
|
|
candidate_matchers.each do |candidate_matcher|
|
|
|
|
candidates.each do |candidate|
|
|
|
|
candidate_matcher.each(candidate,&block)
|
|
|
|
end
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:10:54 -04:00
|
|
|
# Return subjects enumerator
|
|
|
|
#
|
|
|
|
# @return [Enumerable<Subject>]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def subjects(&block)
|
|
|
|
return to_enum(__method__) unless block_given?
|
|
|
|
matchers.each do |matcher|
|
|
|
|
matcher.each(&block)
|
2012-08-14 16:45:34 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|