free_mutant/lib/mutant/reporter/cli.rb

292 lines
5.8 KiB
Ruby

module Mutant
class Reporter
# Reporter that reports in human readable format
class CLI < self
include Equalizer.new(:io)
# Reporter subject
#
# @param [Subject] subject
#
# @return [self]
#
# @api private
#
def subject(subject)
stats.subject
puts("Subject: #{subject.identification}")
end
# Return error stream
#
# @return [IO]
#
# @api private
#
def error_stream
@config.debug? ? io : StringIO.new
end
# Return output stream
#
# @return [IO]
#
# @api private
#
def output_stream
@config.debug? ? io : StringIO.new
end
# Report mutation
#
# @param [Mutation] mutation
#
# @return [self]
#
# @api private
#
def mutation(mutation)
if @config.debug?
colorized_diff(mutation)
end
self
end
# Report config
#
# @param [Mutant::Config] config
#
# @return [self]
#
# @api private
#
def config(config)
puts 'Mutant configuration:'
puts "Matcher: #{config.matcher.inspect}"
puts "Filter: #{config.filter.inspect}"
puts "Strategy: #{config.strategy.inspect}"
end
# Report noop
#
# @param [Killer] killer
#
# @return [self]
#
# @api private
#
def noop(killer)
color, word =
if killer.fail?
[Color::GREEN, 'Alive']
else
[Color::RED, 'Killed']
end
print_killer(color, word, killer)
unless killer.fail?
puts(killer.mutation.source)
stats.noop_fail(killer)
end
self
end
# Reporter killer
#
# @param [Killer] killer
#
# @return [self]
#
# @api private
#
def killer(killer)
stats.killer(killer)
color, word =
if killer.fail?
[Color::RED, 'Alive']
else
[Color::GREEN, 'Killed']
end
print_killer(color, word, killer)
if killer.fail?
colorized_diff(killer.mutation)
end
self
end
# Report errors
#
# @param [Enumerable<Killer>] errors
#
# @api private
#
# @return [self]
#
def errors(errors)
errors.each do |error|
failure(error)
end
puts
puts "subjects: #{stats.subjects}"
puts "mutations: #{stats.mutations}"
puts "noop_fails: #{stats.noop_fails}"
puts "kills: #{stats.kills}"
puts "alive: #{stats.alive}"
puts "mtime: %02.2fs" % stats.time
puts "rtime: %02.2fs" % stats.runtime
end
# Return IO stream
#
# @return [IO]
#
# @api private
#
attr_reader :io
# Return stats
#
# @return [Stats]
#
# @api private
#
attr_reader :stats
private
# Initialize reporter
#
# @param [Config] config
#
# @return [undefined]
#
# @api private
#
def initialize(config)
super
@io = $stdout
@stats = Stats.new
end
# Report failure on killer
#
# @param [Killer] killer
#
# @return [undefined]
#
# @api private
#
def failure(killer)
puts(colorize(Color::RED, "!!! Mutant alive: #{killer.identification} !!!"))
colorized_diff(killer.mutation)
puts("Took: (%02.2fs)" % killer.runtime)
end
# Test for colored output
#
# @return [true]
# returns true if output is colored
#
# @return [false]
# returns false otherwise
#
# @api private
#
def color?
tty?
end
# Colorize message
#
# @param [Color] color
# @param [String] message
#
# @api private
#
# @return [String]
# returns colorized string if color is enabled
# returns unmodified message otherwise
#
def colorize(color, message)
color = Color::NONE unless color?
color.format(message)
end
# Write string to io
#
# @param [String] string
#
# @return [undefined]
#
# @api private
#
def puts(string="\n")
io.puts(string)
end
# Write colorized diff
#
# @param [Mutation] mutation
#
# @return [undefined]
#
# @api private
#
def colorized_diff(mutation)
if mutation.kind_of?(Mutation::Noop)
puts mutation.original_source
return
end
original, current = mutation.original_source, mutation.source
differ = Differ.new(original, current)
diff = color? ? differ.colorized_diff : differ.diff
# FIXME remove this branch before release
if diff.empty?
raise "Unable to create a diff, so ast mutation or to_source has an error!"
end
puts(diff)
self
end
# Print killer
#
# @param [Color] color
# @param [String] word
# @param [Killer] killer
#
# @return [undefined]
#
# @api private
#
def print_killer(color, word, killer)
puts(colorize(color, "#{word}: #{killer.identification} (%02.2fs)" % killer.runtime))
end
# Test for output to tty
#
# @return [true]
# returns true if output is a tty
#
# @return [false]
# returns false otherwise
#
# @api private
#
def tty?
@io.respond_to?(:tty?) && @io.tty?
end
memoize :tty?
end
end
end