Cleanup report printers
This commit is contained in:
parent
add2269d10
commit
ecefef6166
30 changed files with 1388 additions and 827 deletions
|
@ -1,3 +1,3 @@
|
|||
---
|
||||
threshold: 18
|
||||
total_score: 1237
|
||||
total_score: 1240
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
threshold: 30.9
|
||||
threshold: 29.3
|
||||
|
|
|
@ -217,6 +217,16 @@ require 'mutant/reporter/null'
|
|||
require 'mutant/reporter/trace'
|
||||
require 'mutant/reporter/cli'
|
||||
require 'mutant/reporter/cli/printer'
|
||||
require 'mutant/reporter/cli/printer/config'
|
||||
require 'mutant/reporter/cli/printer/env_result'
|
||||
require 'mutant/reporter/cli/printer/env_progress'
|
||||
require 'mutant/reporter/cli/printer/mutation_result'
|
||||
require 'mutant/reporter/cli/printer/mutation_progress_result'
|
||||
require 'mutant/reporter/cli/printer/subject_progress'
|
||||
require 'mutant/reporter/cli/printer/subject_result'
|
||||
require 'mutant/reporter/cli/printer/status'
|
||||
require 'mutant/reporter/cli/printer/status_progressive'
|
||||
require 'mutant/reporter/cli/printer/test_result'
|
||||
require 'mutant/reporter/cli/tput'
|
||||
require 'mutant/reporter/cli/format'
|
||||
require 'mutant/zombifier'
|
||||
|
|
|
@ -53,11 +53,6 @@ module Mutant
|
|||
#
|
||||
# TODO: Move this to a callback registration
|
||||
#
|
||||
# Reporters other than CLI that might exist in future
|
||||
# may only need the final report. So providing a noop callback
|
||||
# registration makes more sense for these.
|
||||
# As only CLI reporters exist currently I do not really care right now.
|
||||
#
|
||||
# @return [Float]
|
||||
#
|
||||
# @api private
|
||||
|
@ -88,7 +83,7 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def report(env)
|
||||
Printer::EnvResult.run(output, env)
|
||||
Printer::EnvResult.call(output, env)
|
||||
self
|
||||
end
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ module Mutant
|
|||
#
|
||||
def format(printer, object)
|
||||
buffer = new_buffer
|
||||
printer.run(Output.new(tty, buffer), object)
|
||||
printer.call(Output.new(tty, buffer), object)
|
||||
buffer.rewind
|
||||
buffer.read
|
||||
end
|
||||
|
|
|
@ -3,25 +3,14 @@ module Mutant
|
|||
class CLI
|
||||
# CLI runner status printer base class
|
||||
class Printer
|
||||
include AbstractType, Delegator, Adamantium::Flat, Concord.new(:output, :object)
|
||||
include AbstractType, Delegator, Adamantium::Flat, Concord.new(:output, :object), Procto.call(:run)
|
||||
|
||||
delegate(:success?)
|
||||
private_class_method :new
|
||||
|
||||
delegate :success?
|
||||
|
||||
NL = "\n".freeze
|
||||
|
||||
# Run printer on object to output
|
||||
#
|
||||
# @param [IO] output
|
||||
# @param [Object] object
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def self.run(output, object)
|
||||
new(output, object).run
|
||||
end
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [self]
|
||||
|
@ -67,7 +56,7 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def visit(printer, object)
|
||||
printer.run(output, object)
|
||||
printer.call(output, object)
|
||||
end
|
||||
|
||||
# Print an info line to output
|
||||
|
@ -133,490 +122,6 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
alias_method :color?, :tty?
|
||||
|
||||
# Printer for runner status
|
||||
class Status < self
|
||||
|
||||
delegate(:active_jobs, :payload)
|
||||
|
||||
# Print progress for collector
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
visit(EnvProgress, payload)
|
||||
job_status
|
||||
info('Active subjects: %d', active_subject_results.length)
|
||||
visit_collection(SubjectProgress, active_subject_results)
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Print worker status
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def job_status
|
||||
return if active_jobs.empty?
|
||||
info('Active Jobs:')
|
||||
active_jobs.sort_by(&:index).each do |job|
|
||||
info('%d: %s', job.index, job.payload.identification)
|
||||
end
|
||||
end
|
||||
|
||||
# Return active subject results
|
||||
#
|
||||
# @return [Array<Result::Subject>]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def active_subject_results
|
||||
active_mutation_jobs = active_jobs.select { |job| job.payload.kind_of?(Mutation) }
|
||||
active_subjects = active_mutation_jobs.map(&:payload).flat_map(&:subject).to_set
|
||||
|
||||
payload.subject_results.select do |subject_result|
|
||||
active_subjects.include?(subject_result.subject)
|
||||
end
|
||||
end
|
||||
|
||||
end # Status
|
||||
|
||||
# Progress printer for configuration
|
||||
class Config < self
|
||||
|
||||
# Report configuration
|
||||
#
|
||||
# @param [Mutant::Config] config
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# rubocop:disable AbcSize
|
||||
#
|
||||
def run
|
||||
info 'Mutant configuration:'
|
||||
info 'Matcher: %s', object.matcher.inspect
|
||||
info 'Integration: %s', object.integration.name
|
||||
info 'Expect Coverage: %0.2f%%', (object.expected_coverage * 100)
|
||||
info 'Jobs: %d', object.jobs
|
||||
info 'Includes: %s', object.includes.inspect
|
||||
info 'Requires: %s', object.requires.inspect
|
||||
self
|
||||
end
|
||||
|
||||
end # Config
|
||||
|
||||
# Env progress printer
|
||||
class EnvProgress < self
|
||||
|
||||
delegate(
|
||||
:coverage,
|
||||
:amount_subjects,
|
||||
:amount_mutations,
|
||||
:amount_mutations_alive,
|
||||
:amount_mutations_killed,
|
||||
:runtime,
|
||||
:killtime,
|
||||
:overhead,
|
||||
:env
|
||||
)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# rubocop:disable MethodLength
|
||||
#
|
||||
def run
|
||||
visit(Config, env.config)
|
||||
info 'Subjects: %s', amount_subjects
|
||||
info 'Mutations: %s', amount_mutations
|
||||
info 'Kills: %s', amount_mutations_killed
|
||||
info 'Alive: %s', amount_mutations_alive
|
||||
info 'Runtime: %0.2fs', runtime
|
||||
info 'Killtime: %0.2fs', killtime
|
||||
info 'Overhead: %0.2f%%', overhead_percent
|
||||
status 'Coverage: %0.2f%%', coverage_percent
|
||||
status 'Expected: %0.2f%%', (env.config.expected_coverage * 100)
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return coverage percent
|
||||
#
|
||||
# @return [Float]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def coverage_percent
|
||||
coverage * 100
|
||||
end
|
||||
|
||||
# Return overhead percent
|
||||
#
|
||||
# @return [Float]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def overhead_percent
|
||||
(overhead / killtime) * 100
|
||||
end
|
||||
|
||||
end # EnvProgress
|
||||
|
||||
# Full env result reporter
|
||||
class EnvResult < self
|
||||
|
||||
delegate(:failed_subject_results)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
visit_collection(SubjectResult, failed_subject_results)
|
||||
visit(EnvProgress, object)
|
||||
self
|
||||
end
|
||||
|
||||
end # EnvResult
|
||||
|
||||
# Subject report printer
|
||||
class SubjectResult < self
|
||||
|
||||
delegate :subject, :failed_mutations, :tests
|
||||
|
||||
# Run report printer
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
status(subject.identification)
|
||||
tests.each do |test|
|
||||
puts("- #{test.identification}")
|
||||
end
|
||||
visit_collection(MutationResult, object.alive_mutation_results)
|
||||
self
|
||||
end
|
||||
|
||||
end # Subject
|
||||
|
||||
# Printer for mutation progress results
|
||||
class MutationProgressResult < self
|
||||
|
||||
SUCCESS = '.'.freeze
|
||||
FAILURE = 'F'.freeze
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
char(success? ? SUCCESS : FAILURE)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Write colorized char
|
||||
#
|
||||
# @param [String] char
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def char(char)
|
||||
output.write(colorize(status_color, char))
|
||||
end
|
||||
|
||||
end # MutationProgressResult
|
||||
|
||||
# Reporter for progressive output format on scheduler Status objects
|
||||
class StatusProgressive < self
|
||||
|
||||
FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
|
||||
|
||||
delegate(
|
||||
:coverage,
|
||||
:runtime,
|
||||
:amount_mutations_killed,
|
||||
:amount_mutations,
|
||||
:amount_mutation_results,
|
||||
:killtime,
|
||||
:overhead
|
||||
)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
status(
|
||||
FORMAT,
|
||||
amount_mutations_killed,
|
||||
amount_mutations,
|
||||
coverage * 100,
|
||||
killtime,
|
||||
runtime,
|
||||
overhead
|
||||
)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return object being printed
|
||||
#
|
||||
# @return [Result::Env]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def object
|
||||
super().payload
|
||||
end
|
||||
end
|
||||
|
||||
# Reporter for subject progress
|
||||
class SubjectProgress < self
|
||||
|
||||
FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
|
||||
|
||||
delegate(
|
||||
:tests,
|
||||
:subject,
|
||||
:coverage,
|
||||
:runtime,
|
||||
:amount_mutations_killed,
|
||||
:amount_mutations,
|
||||
:amount_mutation_results,
|
||||
:killtime,
|
||||
:overhead
|
||||
)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
puts("#{subject.identification} mutations: #{amount_mutations}")
|
||||
print_mutation_results
|
||||
print_progress_bar_finish
|
||||
print_stats
|
||||
print_tests
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Print stats
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_stats
|
||||
status(
|
||||
FORMAT,
|
||||
amount_mutations_killed,
|
||||
amount_mutations,
|
||||
coverage * 100,
|
||||
killtime,
|
||||
runtime,
|
||||
overhead
|
||||
)
|
||||
end
|
||||
|
||||
# Print tests
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_tests
|
||||
tests.each do |test|
|
||||
puts "- #{test.identification}"
|
||||
end
|
||||
end
|
||||
|
||||
# Print progress bar finish
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_progress_bar_finish
|
||||
puts(NL) unless amount_mutation_results.zero?
|
||||
end
|
||||
|
||||
# Print mutation results
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_mutation_results
|
||||
visit_collection(MutationProgressResult, object.mutation_results)
|
||||
end
|
||||
|
||||
end # Subject
|
||||
|
||||
# Reporter for mutation results
|
||||
class MutationResult < self
|
||||
|
||||
delegate :mutation, :test_result
|
||||
|
||||
DIFF_ERROR_MESSAGE =
|
||||
'BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!'.freeze
|
||||
|
||||
MAP = {
|
||||
Mutant::Mutation::Evil => :evil_details,
|
||||
Mutant::Mutation::Neutral => :neutral_details,
|
||||
Mutant::Mutation::Noop => :noop_details
|
||||
}.freeze
|
||||
|
||||
NEUTRAL_MESSAGE =
|
||||
"--- Neutral failure ---\n" \
|
||||
"Original code was inserted unmutated. And the test did NOT PASS.\n" \
|
||||
"Your tests do not pass initially or you found a bug in mutant / unparser.\n" \
|
||||
"Subject AST:\n" \
|
||||
"%s\n" \
|
||||
"Unparsed Source:\n" \
|
||||
"%s\n" \
|
||||
"Test Result:\n".freeze
|
||||
|
||||
NOOP_MESSAGE =
|
||||
"---- Noop failure -----\n" \
|
||||
"No code was inserted. And the test did NOT PASS.\n" \
|
||||
"This is typically a problem of your specs not passing unmutated.\n" \
|
||||
"Test Result:\n".freeze
|
||||
|
||||
FOOTER = '-----------------------'.freeze
|
||||
|
||||
# Run report printer
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
puts(mutation.identification)
|
||||
print_details
|
||||
puts(FOOTER)
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return details
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_details
|
||||
send(MAP.fetch(mutation.class))
|
||||
end
|
||||
|
||||
# Return evil details
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def evil_details
|
||||
original, current = mutation.original_source, mutation.source
|
||||
diff = Mutant::Diff.build(original, current)
|
||||
diff = color? ? diff.colorized_diff : diff.diff
|
||||
puts(diff || ['Original source:', original, 'Mutated Source:', current, DIFF_ERROR_MESSAGE])
|
||||
end
|
||||
|
||||
# Noop details
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def noop_details
|
||||
info(NOOP_MESSAGE)
|
||||
visit_test_result
|
||||
end
|
||||
|
||||
# Neutral details
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def neutral_details
|
||||
info(NEUTRAL_MESSAGE, mutation.subject.node.inspect, mutation.source)
|
||||
visit_test_result
|
||||
end
|
||||
|
||||
# Visit failed test results
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def visit_test_result
|
||||
visit(TestResult, test_result)
|
||||
end
|
||||
|
||||
end # MutationResult
|
||||
|
||||
# Test result reporter
|
||||
class TestResult < self
|
||||
|
||||
delegate :tests, :runtime
|
||||
|
||||
# Run test result reporter
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
status('- %d @ runtime: %s', tests.length, runtime)
|
||||
tests.each do |test|
|
||||
puts(" - #{test.identification}")
|
||||
end
|
||||
puts('Test Output:')
|
||||
puts(object.output)
|
||||
end
|
||||
|
||||
# Test if test result is successful
|
||||
#
|
||||
# Only used to determine color.
|
||||
#
|
||||
# @return [false]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def success?
|
||||
false
|
||||
end
|
||||
|
||||
end # TestResult
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
|
|
32
lib/mutant/reporter/cli/printer/config.rb
Normal file
32
lib/mutant/reporter/cli/printer/config.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Printer for mutation config
|
||||
class Config < self
|
||||
|
||||
# Report configuration
|
||||
#
|
||||
# @param [Mutant::Config] config
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# rubocop:disable AbcSize
|
||||
#
|
||||
def run
|
||||
info 'Mutant configuration:'
|
||||
info 'Matcher: %s', object.matcher.inspect
|
||||
info 'Integration: %s', object.integration.name
|
||||
info 'Expect Coverage: %0.2f%%', (object.expected_coverage * 100)
|
||||
info 'Jobs: %d', object.jobs
|
||||
info 'Includes: %s', object.includes
|
||||
info 'Requires: %s', object.requires
|
||||
end
|
||||
|
||||
end # Config
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
66
lib/mutant/reporter/cli/printer/env_progress.rb
Normal file
66
lib/mutant/reporter/cli/printer/env_progress.rb
Normal file
|
@ -0,0 +1,66 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Env progress printer
|
||||
class EnvProgress < self
|
||||
delegate(
|
||||
:coverage,
|
||||
:amount_subjects,
|
||||
:amount_mutations,
|
||||
:amount_mutations_alive,
|
||||
:amount_mutations_killed,
|
||||
:runtime,
|
||||
:killtime,
|
||||
:overhead,
|
||||
:env
|
||||
)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# rubocop:disable MethodLength
|
||||
# rubocop:disable AbcSize
|
||||
#
|
||||
def run
|
||||
visit(Config, env.config)
|
||||
info 'Subjects: %s', amount_subjects
|
||||
info 'Mutations: %s', amount_mutations
|
||||
info 'Kills: %s', amount_mutations_killed
|
||||
info 'Alive: %s', amount_mutations_alive
|
||||
info 'Runtime: %0.2fs', runtime
|
||||
info 'Killtime: %0.2fs', killtime
|
||||
info 'Overhead: %0.2f%%', overhead_percent
|
||||
status 'Coverage: %0.2f%%', coverage_percent
|
||||
status 'Expected: %0.2f%%', (env.config.expected_coverage * 100)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return coverage percent
|
||||
#
|
||||
# @return [Float]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def coverage_percent
|
||||
coverage * 100
|
||||
end
|
||||
|
||||
# Return overhead percent
|
||||
#
|
||||
# @return [Float]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def overhead_percent
|
||||
(overhead / killtime) * 100
|
||||
end
|
||||
end # EnvProgress
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
23
lib/mutant/reporter/cli/printer/env_result.rb
Normal file
23
lib/mutant/reporter/cli/printer/env_result.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Full env result reporter
|
||||
class EnvResult < self
|
||||
delegate(:failed_subject_results)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
visit_collection(SubjectResult, failed_subject_results)
|
||||
visit(EnvProgress, object)
|
||||
end
|
||||
end # EnvResult
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
37
lib/mutant/reporter/cli/printer/mutation_progress_result.rb
Normal file
37
lib/mutant/reporter/cli/printer/mutation_progress_result.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Printer for mutation progress results
|
||||
class MutationProgressResult < self
|
||||
SUCCESS = '.'.freeze
|
||||
FAILURE = 'F'.freeze
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
char(success? ? SUCCESS : FAILURE)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Write colorized char
|
||||
#
|
||||
# @param [String] char
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def char(char)
|
||||
output.write(colorize(status_color, char))
|
||||
end
|
||||
end # MutationProgressResult
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
151
lib/mutant/reporter/cli/printer/mutation_result.rb
Normal file
151
lib/mutant/reporter/cli/printer/mutation_result.rb
Normal file
|
@ -0,0 +1,151 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Reporter for mutation results
|
||||
class MutationResult < self
|
||||
|
||||
delegate :mutation, :test_result
|
||||
|
||||
DIFF_ERROR_MESSAGE =
|
||||
'BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!'.freeze
|
||||
|
||||
MAP = {
|
||||
Mutant::Mutation::Evil => :evil_details,
|
||||
Mutant::Mutation::Neutral => :neutral_details,
|
||||
Mutant::Mutation::Noop => :noop_details
|
||||
}.freeze
|
||||
|
||||
NEUTRAL_MESSAGE =
|
||||
"--- Neutral failure ---\n" \
|
||||
"Original code was inserted unmutated. And the test did NOT PASS.\n" \
|
||||
"Your tests do not pass initially or you found a bug in mutant / unparser.\n" \
|
||||
"Subject AST:\n" \
|
||||
"%s\n" \
|
||||
"Unparsed Source:\n" \
|
||||
"%s\n" \
|
||||
"Test Result:\n".freeze
|
||||
|
||||
NO_DIFF_MESSAGE =
|
||||
"--- Internal failure ---\n" \
|
||||
"BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!\n" \
|
||||
"Original unparsed source:\n" \
|
||||
"%s\n" \
|
||||
"Original AST:\n" \
|
||||
"%s\n" \
|
||||
"Mutated unparsed source:\n" \
|
||||
"%s\n" \
|
||||
"Mutated AST:\n" \
|
||||
"%s\n".freeze
|
||||
|
||||
NOOP_MESSAGE =
|
||||
"---- Noop failure -----\n" \
|
||||
"No code was inserted. And the test did NOT PASS.\n" \
|
||||
"This is typically a problem of your specs not passing unmutated.\n" \
|
||||
"Test Result:\n".freeze
|
||||
|
||||
FOOTER = '-----------------------'.freeze
|
||||
|
||||
# Run report printer
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
puts(mutation.identification)
|
||||
print_details
|
||||
puts(FOOTER)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return details
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_details
|
||||
__send__(MAP.fetch(mutation.class))
|
||||
end
|
||||
|
||||
# Return evil details
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def evil_details
|
||||
diff = Diff.build(mutation.original_source, mutation.source)
|
||||
diff = color? ? diff.colorized_diff : diff.diff
|
||||
if diff
|
||||
output.write(diff)
|
||||
else
|
||||
print_no_diff_message
|
||||
end
|
||||
end
|
||||
|
||||
# Print no diff message
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_no_diff_message
|
||||
info(
|
||||
NO_DIFF_MESSAGE,
|
||||
mutation.original_source,
|
||||
original_node.inspect,
|
||||
mutation.source,
|
||||
mutation.node.inspect
|
||||
)
|
||||
end
|
||||
|
||||
# Noop details
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def noop_details
|
||||
info(NOOP_MESSAGE)
|
||||
visit_test_result
|
||||
end
|
||||
|
||||
# Neutral details
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def neutral_details
|
||||
info(NEUTRAL_MESSAGE, original_node.inspect, mutation.source)
|
||||
visit_test_result
|
||||
end
|
||||
|
||||
# Visit failed test results
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def visit_test_result
|
||||
visit(TestResult, test_result)
|
||||
end
|
||||
|
||||
# Return original node
|
||||
#
|
||||
# @return [Parser::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def original_node
|
||||
mutation.subject.node
|
||||
end
|
||||
|
||||
end # MutationResult
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
60
lib/mutant/reporter/cli/printer/status.rb
Normal file
60
lib/mutant/reporter/cli/printer/status.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Printer for runner status
|
||||
class Status < self
|
||||
|
||||
delegate(:active_jobs, :payload)
|
||||
|
||||
ACTIVE_JOB_HEADER = 'Active Jobs:'.freeze
|
||||
ACTIVE_JOB_FORMAT = '%d: %s'.freeze
|
||||
|
||||
# Print progress for collector
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
visit(EnvProgress, payload)
|
||||
job_status
|
||||
info('Active subjects: %d', active_subject_results.length)
|
||||
visit_collection(SubjectProgress, active_subject_results)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Print worker status
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def job_status
|
||||
return if active_jobs.empty?
|
||||
info(ACTIVE_JOB_HEADER)
|
||||
active_jobs.sort_by(&:index).each do |job|
|
||||
info(ACTIVE_JOB_FORMAT, job.index, job.payload.identification)
|
||||
end
|
||||
end
|
||||
|
||||
# Return active subject results
|
||||
#
|
||||
# @return [Array<Result::Subject>]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def active_subject_results
|
||||
active_subjects = active_jobs.map(&:payload).flat_map(&:subject)
|
||||
|
||||
payload.subject_results.select do |subject_result|
|
||||
active_subjects.include?(subject_result.subject)
|
||||
end
|
||||
end
|
||||
|
||||
end # Status
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
52
lib/mutant/reporter/cli/printer/status_progressive.rb
Normal file
52
lib/mutant/reporter/cli/printer/status_progressive.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Reporter for progressive output format on scheduler Status objects
|
||||
class StatusProgressive < self
|
||||
FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
|
||||
|
||||
delegate(
|
||||
:coverage,
|
||||
:runtime,
|
||||
:amount_mutations_killed,
|
||||
:amount_mutations,
|
||||
:amount_mutation_results,
|
||||
:killtime,
|
||||
:overhead
|
||||
)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
status(
|
||||
FORMAT,
|
||||
amount_mutations_killed,
|
||||
amount_mutations,
|
||||
coverage * 100,
|
||||
killtime,
|
||||
runtime,
|
||||
overhead
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return object being printed
|
||||
#
|
||||
# @return [Result::Env]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def object
|
||||
super.payload
|
||||
end
|
||||
end # StatusProgressive
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
90
lib/mutant/reporter/cli/printer/subject_progress.rb
Normal file
90
lib/mutant/reporter/cli/printer/subject_progress.rb
Normal file
|
@ -0,0 +1,90 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Reporter for subject progress
|
||||
class SubjectProgress < self
|
||||
FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
|
||||
|
||||
delegate(
|
||||
:tests,
|
||||
:subject,
|
||||
:coverage,
|
||||
:runtime,
|
||||
:amount_mutations_killed,
|
||||
:amount_mutations,
|
||||
:amount_mutation_results,
|
||||
:killtime,
|
||||
:overhead
|
||||
)
|
||||
|
||||
# Run printer
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
puts("#{subject.identification} mutations: #{amount_mutations}")
|
||||
print_mutation_results
|
||||
print_progress_bar_finish
|
||||
print_stats
|
||||
print_tests
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Print stats
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_stats
|
||||
status(
|
||||
FORMAT,
|
||||
amount_mutations_killed,
|
||||
amount_mutations,
|
||||
coverage * 100,
|
||||
killtime,
|
||||
runtime,
|
||||
overhead
|
||||
)
|
||||
end
|
||||
|
||||
# Print tests
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_tests
|
||||
tests.each do |test|
|
||||
puts "- #{test.identification}"
|
||||
end
|
||||
end
|
||||
|
||||
# Print progress bar finish
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_progress_bar_finish
|
||||
puts(nil) unless amount_mutation_results.zero?
|
||||
end
|
||||
|
||||
# Print mutation results
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def print_mutation_results
|
||||
visit_collection(MutationProgressResult, object.mutation_results)
|
||||
end
|
||||
end # SubjectProgress
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
28
lib/mutant/reporter/cli/printer/subject_result.rb
Normal file
28
lib/mutant/reporter/cli/printer/subject_result.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Subject result printer
|
||||
class SubjectResult < self
|
||||
|
||||
delegate :subject, :alive_mutation_results, :tests
|
||||
|
||||
# Run report printer
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
status(subject.identification)
|
||||
tests.each do |test|
|
||||
puts("- #{test.identification}")
|
||||
end
|
||||
visit_collection(MutationResult, alive_mutation_results)
|
||||
end
|
||||
|
||||
end # SubjectResult
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
33
lib/mutant/reporter/cli/printer/test_result.rb
Normal file
33
lib/mutant/reporter/cli/printer/test_result.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
module Mutant
|
||||
class Reporter
|
||||
class CLI
|
||||
class Printer
|
||||
# Test result reporter
|
||||
class TestResult < self
|
||||
|
||||
delegate :tests, :runtime
|
||||
|
||||
STATUS_FORMAT = '- %d @ runtime: %s'.freeze
|
||||
OUTPUT_HEADER = 'Test Output:'.freeze
|
||||
TEST_FORMAT = ' - %s'.freeze
|
||||
|
||||
# Run test result reporter
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
info(STATUS_FORMAT, tests.length, runtime)
|
||||
tests.each do |test|
|
||||
info(TEST_FORMAT, test.identification)
|
||||
end
|
||||
puts(OUTPUT_HEADER)
|
||||
puts(object.output)
|
||||
end
|
||||
|
||||
end # TestResult
|
||||
end # Printer
|
||||
end # CLI
|
||||
end # Reporter
|
||||
end # Mutant
|
|
@ -14,6 +14,14 @@ module SharedContext
|
|||
end
|
||||
end
|
||||
|
||||
def it_reports(expected_content)
|
||||
it 'writes expected report to output' do
|
||||
described_class.call(output, reportable)
|
||||
output.rewind
|
||||
expect(output.read).to eql(strip_indent(expected_content))
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:disable MethodLength
|
||||
# rubocop:disable AbcSize
|
||||
def setup_shared_context
|
||||
|
@ -24,6 +32,7 @@ module SharedContext
|
|||
let(:job_b_result) { Mutant::Runner::JobResult.new(job: job_b, result: mutation_b_result) }
|
||||
let(:test_a) { double('test a', identification: 'test-a') }
|
||||
let(:test_b) { double('test b', identification: 'test-b') }
|
||||
let(:output) { StringIO.new }
|
||||
let(:matchable_scopes) { double('matchable scopes', length: 10) }
|
||||
let(:message_sequence) { FakeActor::MessageSequence.new }
|
||||
let(:mutations) { [mutation_a, mutation_b] }
|
||||
|
@ -31,10 +40,7 @@ module SharedContext
|
|||
let(:mutation_b_node) { s(:nil) }
|
||||
let(:mutation_b) { Mutant::Mutation::Evil.new(subject_a, mutation_b_node) }
|
||||
let(:mutation_a) { Mutant::Mutation::Evil.new(subject_a, mutation_a_node) }
|
||||
|
||||
before do
|
||||
allow(subject_a).to receive(:mutations).and_return([mutation_a, mutation_b])
|
||||
end
|
||||
let(:subject_a_node) { s(:true) }
|
||||
|
||||
let(:status) do
|
||||
Mutant::Parallel::Status.new(
|
||||
|
@ -54,13 +60,17 @@ module SharedContext
|
|||
let(:subject_a) do
|
||||
double(
|
||||
'subject a',
|
||||
node: s(:true),
|
||||
source: 'true',
|
||||
node: subject_a_node,
|
||||
source: Unparser.unparse(subject_a_node),
|
||||
tests: [test_a],
|
||||
identification: 'subject-a'
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(subject_a).to receive(:mutations).and_return([mutation_a, mutation_b])
|
||||
end
|
||||
|
||||
let(:env_result) do
|
||||
Mutant::Result::Env.new(
|
||||
env: env,
|
||||
|
|
33
spec/unit/mutant/reporter/cli/printer/config_spec.rb
Normal file
33
spec/unit/mutant/reporter/cli/printer/config_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::Config do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { config }
|
||||
|
||||
describe '.call' do
|
||||
context 'on default config' do
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'with non default coverage expectation' do
|
||||
update(:config) { { expected_coverage: 0.1r } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 10.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
end
|
76
spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb
Normal file
76
spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb
Normal file
|
@ -0,0 +1,76 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::EnvProgress do
|
||||
setup_shared_context
|
||||
|
||||
update(:config) { { expected_coverage: 0.1r } }
|
||||
|
||||
let(:reportable) { env_result }
|
||||
|
||||
describe '.call' do
|
||||
context 'without progress' do
|
||||
update(:subject_a_result) { { mutation_results: [] } }
|
||||
|
||||
it_reports <<-'STR'
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 10.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 0
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 0.00s
|
||||
Overhead: Inf%
|
||||
Coverage: 0.00%
|
||||
Expected: 10.00%
|
||||
STR
|
||||
end
|
||||
|
||||
context 'on full coverage' do
|
||||
it_reports <<-'STR'
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 10.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 10.00%
|
||||
STR
|
||||
end
|
||||
|
||||
context 'on partial coverage' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
it_reports <<-'STR'
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 10.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 1
|
||||
Alive: 1
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 50.00%
|
||||
Expected: 10.00%
|
||||
STR
|
||||
end
|
||||
end
|
||||
end
|
35
spec/unit/mutant/reporter/cli/printer/env_result_spec.rb
Normal file
35
spec/unit/mutant/reporter/cli/printer/env_result_spec.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::EnvResult do
|
||||
setup_shared_context
|
||||
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
let(:reportable) { env_result }
|
||||
|
||||
describe '.call' do
|
||||
it_reports <<-'STR'
|
||||
subject-a
|
||||
- test-a
|
||||
evil:subject-a:d27d2
|
||||
@@ -1,2 +1,2 @@
|
||||
-true
|
||||
+false
|
||||
-----------------------
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 1
|
||||
Alive: 1
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 50.00%
|
||||
Expected: 100.00%
|
||||
STR
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::MutationProgressResult do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { mutation_a_result }
|
||||
|
||||
before do
|
||||
allow(output).to receive(:tty?).and_return(true)
|
||||
end
|
||||
|
||||
describe '.run' do
|
||||
context 'on killed mutant' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
it_reports Mutant::Color::RED.format('F')
|
||||
end
|
||||
|
||||
context 'on alive mutant' do
|
||||
update(:mutation_a_test_result) { { passed: false } }
|
||||
|
||||
it_reports Mutant::Color::GREEN.format('.')
|
||||
end
|
||||
end
|
||||
end
|
110
spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb
Normal file
110
spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb
Normal file
|
@ -0,0 +1,110 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::MutationResult do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { mutation_a_result }
|
||||
|
||||
describe '.call' do
|
||||
context 'failed kill' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
context 'on evil mutation' do
|
||||
context 'with a diff' do
|
||||
context 'on a tty' do
|
||||
before do
|
||||
allow(output).to receive(:tty?).and_return(true)
|
||||
end
|
||||
|
||||
it_reports(
|
||||
[
|
||||
[Mutant::Color::NONE, "evil:subject-a:d27d2\n"],
|
||||
[Mutant::Color::NONE, "@@ -1,2 +1,2 @@\n"],
|
||||
[Mutant::Color::RED, "-true\n"],
|
||||
[Mutant::Color::GREEN, "+false\n"],
|
||||
[Mutant::Color::NONE, "-----------------------\n"]
|
||||
].map { |color, text| color.format(text) }.join
|
||||
)
|
||||
end
|
||||
|
||||
context 'on non tty' do
|
||||
it_reports(<<-'STR')
|
||||
evil:subject-a:d27d2
|
||||
@@ -1,2 +1,2 @@
|
||||
-true
|
||||
+false
|
||||
-----------------------
|
||||
STR
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a diff' do
|
||||
# This is intentionally invalid AST mutant might produce
|
||||
let(:subject_a_node) { s(:lvar, :super) }
|
||||
|
||||
# Unparses exactly the same way as above node
|
||||
let(:mutation_a_node) { s(:zsuper) }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
evil:subject-a:a5bc7
|
||||
--- Internal failure ---
|
||||
BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!
|
||||
Original unparsed source:
|
||||
super
|
||||
Original AST:
|
||||
(lvar :super)
|
||||
Mutated unparsed source:
|
||||
super
|
||||
Mutated AST:
|
||||
(zsuper)
|
||||
-----------------------
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
|
||||
context 'on neutral mutation' do
|
||||
update(:mutation_a_test_result) { { passed: false } }
|
||||
|
||||
let(:mutation_a) do
|
||||
Mutant::Mutation::Neutral.new(subject_a, s(:true))
|
||||
end
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
neutral:subject-a:d5318
|
||||
--- Neutral failure ---
|
||||
Original code was inserted unmutated. And the test did NOT PASS.
|
||||
Your tests do not pass initially or you found a bug in mutant / unparser.
|
||||
Subject AST:
|
||||
(true)
|
||||
Unparsed Source:
|
||||
true
|
||||
Test Result:
|
||||
- 1 @ runtime: 1.0
|
||||
- test-a
|
||||
Test Output:
|
||||
mutation a test result output
|
||||
-----------------------
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'on noop mutation' do
|
||||
update(:mutation_a_test_result) { { passed: false } }
|
||||
|
||||
let(:mutation_a) do
|
||||
Mutant::Mutation::Noop.new(subject_a, s(:true))
|
||||
end
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
noop:subject-a:d5318
|
||||
---- Noop failure -----
|
||||
No code was inserted. And the test did NOT PASS.
|
||||
This is typically a problem of your specs not passing unmutated.
|
||||
Test Result:
|
||||
- 1 @ runtime: 1.0
|
||||
- test-a
|
||||
Test Output:
|
||||
mutation a test result output
|
||||
-----------------------
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::StatusProgressive do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { status }
|
||||
|
||||
describe '.call' do
|
||||
context 'with empty scheduler' do
|
||||
update(:env_result) { { subject_results: [] } }
|
||||
|
||||
it_reports <<-REPORT
|
||||
(00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s
|
||||
REPORT
|
||||
|
||||
context 'on non default coverage expectation' do
|
||||
update(:config) { { expected_coverage: 0.1r } }
|
||||
|
||||
it_reports <<-REPORT
|
||||
(00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
|
||||
context 'with scheduler active on one subject' do
|
||||
context 'without progress' do
|
||||
update(:status) { { active_jobs: [].to_set } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
(02/02) 100% - killtime: 2.00s runtime: 4.00s overhead: 2.00s
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'with progress' do
|
||||
update(:status) { { active_jobs: [job_b, job_a].to_set } }
|
||||
|
||||
context 'on failure' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
(01/02) 50% - killtime: 2.00s runtime: 4.00s overhead: 2.00s
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'on success' do
|
||||
it_reports(<<-REPORT)
|
||||
(02/02) 100% - killtime: 2.00s runtime: 4.00s overhead: 2.00s
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
145
spec/unit/mutant/reporter/cli/printer/status_spec.rb
Normal file
145
spec/unit/mutant/reporter/cli/printer/status_spec.rb
Normal file
|
@ -0,0 +1,145 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::Status do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { status }
|
||||
|
||||
describe '.call' do
|
||||
context 'with empty scheduler' do
|
||||
update(:env_result) { { subject_results: [] } }
|
||||
|
||||
it_reports <<-REPORT
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 0
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 0.00s
|
||||
Overhead: Inf%
|
||||
Coverage: 0.00%
|
||||
Expected: 100.00%
|
||||
Active subjects: 0
|
||||
REPORT
|
||||
|
||||
context 'on non default coverage expectation' do
|
||||
update(:config) { { expected_coverage: 0.1r } }
|
||||
|
||||
it_reports <<-REPORT
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 10.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 0
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 0.00s
|
||||
Overhead: Inf%
|
||||
Coverage: 0.00%
|
||||
Expected: 10.00%
|
||||
Active subjects: 0
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
|
||||
context 'with scheduler active on one subject' do
|
||||
context 'without progress' do
|
||||
update(:status) { { active_jobs: [].to_set } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 100.00%
|
||||
Active subjects: 0
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'with progress' do
|
||||
update(:status) { { active_jobs: [job_b, job_a].to_set } }
|
||||
|
||||
context 'on failure' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 1
|
||||
Alive: 1
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 50.00%
|
||||
Expected: 100.00%
|
||||
Active Jobs:
|
||||
0: evil:subject-a:d27d2
|
||||
1: evil:subject-a:d5a9d
|
||||
Active subjects: 1
|
||||
subject-a mutations: 2
|
||||
F.
|
||||
(01/02) 50% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
|
||||
- test-a
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'on success' do
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 100.00%
|
||||
Active Jobs:
|
||||
0: evil:subject-a:d27d2
|
||||
1: evil:subject-a:d5a9d
|
||||
Active subjects: 1
|
||||
subject-a mutations: 2
|
||||
..
|
||||
(02/02) 100% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
|
||||
- test-a
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::SubjectProgress do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { subject_a_result }
|
||||
|
||||
describe '.call' do
|
||||
context 'on full coverage' do
|
||||
it_reports <<-'STR'
|
||||
subject-a mutations: 2
|
||||
..
|
||||
(02/02) 100% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
|
||||
- test-a
|
||||
STR
|
||||
end
|
||||
|
||||
context 'on partial coverage' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
it_reports <<-'STR'
|
||||
subject-a mutations: 2
|
||||
F.
|
||||
(01/02) 50% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
|
||||
- test-a
|
||||
STR
|
||||
end
|
||||
|
||||
context 'without results' do
|
||||
update(:subject_a_result) { { mutation_results: [] } }
|
||||
|
||||
it_reports <<-'STR'
|
||||
subject-a mutations: 2
|
||||
(00/02) 0% - killtime: 0.00s runtime: 0.00s overhead: 0.00s
|
||||
- test-a
|
||||
STR
|
||||
end
|
||||
end
|
||||
end
|
37
spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb
Normal file
37
spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::SubjectResult do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { subject_a_result }
|
||||
|
||||
describe '.call' do
|
||||
context 'on full coverage' do
|
||||
it_reports <<-'STR'
|
||||
subject-a
|
||||
- test-a
|
||||
STR
|
||||
end
|
||||
|
||||
context 'on partial coverage' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
it_reports <<-'STR'
|
||||
subject-a
|
||||
- test-a
|
||||
evil:subject-a:d27d2
|
||||
@@ -1,2 +1,2 @@
|
||||
-true
|
||||
+false
|
||||
-----------------------
|
||||
STR
|
||||
end
|
||||
|
||||
context 'without results' do
|
||||
update(:subject_a_result) { { mutation_results: [] } }
|
||||
|
||||
it_reports <<-'STR'
|
||||
subject-a
|
||||
- test-a
|
||||
STR
|
||||
end
|
||||
end
|
||||
end
|
14
spec/unit/mutant/reporter/cli/printer/test_result_spec.rb
Normal file
14
spec/unit/mutant/reporter/cli/printer/test_result_spec.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer::TestResult do
|
||||
setup_shared_context
|
||||
|
||||
let(:reportable) { mutation_a_test_result }
|
||||
|
||||
describe '.call' do
|
||||
it_reports <<-'STR'
|
||||
- 1 @ runtime: 1.0
|
||||
- test-a
|
||||
Test Output:
|
||||
mutation a test result output
|
||||
STR
|
||||
end
|
||||
end
|
140
spec/unit/mutant/reporter/cli/printer_spec.rb
Normal file
140
spec/unit/mutant/reporter/cli/printer_spec.rb
Normal file
|
@ -0,0 +1,140 @@
|
|||
RSpec.describe Mutant::Reporter::CLI::Printer do
|
||||
let(:output) { StringIO.new }
|
||||
|
||||
subject { class_under_test.call(output, reportable) }
|
||||
|
||||
def self.it_reports(expectation)
|
||||
it 'writes expected report' do
|
||||
allow(output).to receive(:tty?).and_return(tty?)
|
||||
subject
|
||||
output.rewind
|
||||
expect(output.read).to eql(strip_indent(expectation))
|
||||
end
|
||||
end
|
||||
|
||||
let(:reportable) { double('Reportable', success?: success?) }
|
||||
let(:tty?) { true }
|
||||
let(:success?) { true }
|
||||
|
||||
context '.call' do
|
||||
let(:class_under_test) do
|
||||
Class.new(described_class) do
|
||||
def run
|
||||
puts object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:reportable) { 'foo' }
|
||||
|
||||
it_reports "foo\n"
|
||||
end
|
||||
|
||||
context '#status' do
|
||||
let(:class_under_test) do
|
||||
Class.new(described_class) do
|
||||
def run
|
||||
status('foo %s', 'bar')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'on tty' do
|
||||
context 'on success' do
|
||||
it_reports Mutant::Color::GREEN.format('foo bar') << "\n"
|
||||
end
|
||||
|
||||
context 'on failure' do
|
||||
let(:success?) { false }
|
||||
it_reports Mutant::Color::RED.format('foo bar') << "\n"
|
||||
end
|
||||
end
|
||||
|
||||
context 'on no tty' do
|
||||
let(:tty?) { false }
|
||||
|
||||
context 'on success' do
|
||||
it_reports "foo bar\n"
|
||||
end
|
||||
|
||||
context 'on failure' do
|
||||
let(:success?) { false }
|
||||
|
||||
it_reports "foo bar\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#visit_collection' do
|
||||
let(:class_under_test) do
|
||||
reporter = nested_reporter
|
||||
Class.new(described_class) do
|
||||
define_method(:run) do
|
||||
visit_collection(reporter, %w[foo bar])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:nested_reporter) do
|
||||
Class.new(described_class) do
|
||||
def run
|
||||
puts object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_reports "foo\nbar\n"
|
||||
end
|
||||
|
||||
context '#visit' do
|
||||
let(:class_under_test) do
|
||||
reporter = nested_reporter
|
||||
Class.new(described_class) do
|
||||
define_method(:run) do
|
||||
visit(reporter, 'foo')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:nested_reporter) do
|
||||
Class.new(described_class) do
|
||||
def run
|
||||
puts object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_reports "foo\n"
|
||||
end
|
||||
|
||||
context '#info' do
|
||||
let(:class_under_test) do
|
||||
Class.new(described_class) do
|
||||
def run
|
||||
info('%s - %s', 'foo', 'bar')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_reports "foo - bar\n"
|
||||
end
|
||||
|
||||
context '#colorize' do
|
||||
let(:class_under_test) do
|
||||
Class.new(described_class) do
|
||||
def run
|
||||
puts(colorize(Mutant::Color::RED, 'foo'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when output is a tty?' do
|
||||
it_reports Mutant::Color::RED.format('foo') << "\n"
|
||||
end
|
||||
|
||||
context 'when output is NOT a tty?' do
|
||||
let(:tty?) { false }
|
||||
it_reports "foo\n"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,8 +19,10 @@ RSpec.describe Mutant::Reporter::CLI do
|
|||
)
|
||||
end
|
||||
|
||||
let(:tty?) { false }
|
||||
|
||||
let(:progressive_format) do
|
||||
described_class::Format::Progressive.new(tty: false)
|
||||
described_class::Format::Progressive.new(tty: tty?)
|
||||
end
|
||||
|
||||
let(:format) { framed_format }
|
||||
|
@ -128,21 +130,85 @@ RSpec.describe Mutant::Reporter::CLI do
|
|||
REPORT
|
||||
end
|
||||
|
||||
context 'with non default coverage expectation' do
|
||||
let(:format) { progressive_format }
|
||||
update(:config) { { expected_coverage: 0.1r } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 10.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'on framed format' do
|
||||
it_reports '[tput-prepare]'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#report' do
|
||||
subject { object.report(env_result) }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 100.00%
|
||||
REPORT
|
||||
end
|
||||
|
||||
describe '#progress' do
|
||||
subject { object.progress(status) }
|
||||
|
||||
context 'on framed format' do
|
||||
let(:format) { framed_format }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
[tput-restore]Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 100.00%
|
||||
Active subjects: 0
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'on progressive format' do
|
||||
let(:format) { progressive_format }
|
||||
|
||||
context 'with empty scheduler' do
|
||||
update(:env_result) { { subject_results: [] } }
|
||||
|
||||
it_reports "(00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s\n"
|
||||
let(:tty?) { true }
|
||||
|
||||
it_reports Mutant::Color::RED.format('(00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s') << "\n"
|
||||
end
|
||||
|
||||
context 'with last mutation present' do
|
||||
|
@ -159,315 +225,5 @@ RSpec.describe Mutant::Reporter::CLI do
|
|||
end
|
||||
end
|
||||
|
||||
context 'on framed format' do
|
||||
context 'with empty scheduler' do
|
||||
update(:env_result) { { subject_results: [] } }
|
||||
|
||||
it_reports <<-REPORT
|
||||
[tput-restore]Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 0
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 0.00s
|
||||
Overhead: Inf%
|
||||
Coverage: 0.00%
|
||||
Expected: 100.00%
|
||||
Active subjects: 0
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'with scheduler active on one subject' do
|
||||
context 'without progress' do
|
||||
update(:status) { { active_jobs: [].to_set } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
[tput-restore]Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 100.00%
|
||||
Active subjects: 0
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'with progress' do
|
||||
update(:status) { { active_jobs: [job_a].to_set } }
|
||||
|
||||
context 'on failure' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
[tput-restore]Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 1
|
||||
Alive: 1
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 50.00%
|
||||
Expected: 100.00%
|
||||
Active Jobs:
|
||||
0: evil:subject-a:d27d2
|
||||
Active subjects: 1
|
||||
subject-a mutations: 2
|
||||
F.
|
||||
(01/02) 50% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
|
||||
- test-a
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'on success' do
|
||||
it_reports(<<-REPORT)
|
||||
[tput-restore]Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 100.00%
|
||||
Active Jobs:
|
||||
0: evil:subject-a:d27d2
|
||||
Active subjects: 1
|
||||
subject-a mutations: 2
|
||||
..
|
||||
(02/02) 100% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
|
||||
- test-a
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#report' do
|
||||
subject { object.report(status.payload) }
|
||||
|
||||
context 'with full coverage' do
|
||||
it_reports(<<-REPORT)
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 2
|
||||
Alive: 0
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 100.00%
|
||||
Expected: 100.00%
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'and partial coverage' do
|
||||
update(:mutation_a_test_result) { { passed: true } }
|
||||
|
||||
context 'on evil mutation' do
|
||||
context 'with a diff' do
|
||||
it_reports(<<-REPORT)
|
||||
subject-a
|
||||
- test-a
|
||||
evil:subject-a:d27d2
|
||||
@@ -1,2 +1,2 @@
|
||||
-true
|
||||
+false
|
||||
-----------------------
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 1
|
||||
Alive: 1
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 50.00%
|
||||
Expected: 100.00%
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'without a diff' do
|
||||
let(:mutation_a_node) { s(:true) }
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
subject-a
|
||||
- test-a
|
||||
evil:subject-a:d5318
|
||||
Original source:
|
||||
true
|
||||
Mutated Source:
|
||||
true
|
||||
BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!
|
||||
-----------------------
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 1
|
||||
Alive: 1
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 50.00%
|
||||
Expected: 100.00%
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
|
||||
context 'on neutral mutation' do
|
||||
update(:mutation_a_test_result) { { passed: false } }
|
||||
|
||||
let(:mutation_a) do
|
||||
Mutant::Mutation::Neutral.new(subject_a, s(:true))
|
||||
end
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
subject-a
|
||||
- test-a
|
||||
neutral:subject-a:d5318
|
||||
--- Neutral failure ---
|
||||
Original code was inserted unmutated. And the test did NOT PASS.
|
||||
Your tests do not pass initially or you found a bug in mutant / unparser.
|
||||
Subject AST:
|
||||
(true)
|
||||
Unparsed Source:
|
||||
true
|
||||
Test Result:
|
||||
- 1 @ runtime: 1.0
|
||||
- test-a
|
||||
Test Output:
|
||||
mutation a test result output
|
||||
-----------------------
|
||||
neutral:subject-a:d5318
|
||||
--- Neutral failure ---
|
||||
Original code was inserted unmutated. And the test did NOT PASS.
|
||||
Your tests do not pass initially or you found a bug in mutant / unparser.
|
||||
Subject AST:
|
||||
(true)
|
||||
Unparsed Source:
|
||||
true
|
||||
Test Result:
|
||||
- 1 @ runtime: 1.0
|
||||
- test-a
|
||||
Test Output:
|
||||
mutation b test result output
|
||||
-----------------------
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 0
|
||||
Alive: 2
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 0.00%
|
||||
Expected: 100.00%
|
||||
REPORT
|
||||
end
|
||||
|
||||
context 'on noop mutation' do
|
||||
update(:mutation_a_test_result) { { passed: false } }
|
||||
|
||||
let(:mutation_a) do
|
||||
Mutant::Mutation::Noop.new(subject_a, s(:true))
|
||||
end
|
||||
|
||||
it_reports(<<-REPORT)
|
||||
subject-a
|
||||
- test-a
|
||||
noop:subject-a:d5318
|
||||
---- Noop failure -----
|
||||
No code was inserted. And the test did NOT PASS.
|
||||
This is typically a problem of your specs not passing unmutated.
|
||||
Test Result:
|
||||
- 1 @ runtime: 1.0
|
||||
- test-a
|
||||
Test Output:
|
||||
mutation a test result output
|
||||
-----------------------
|
||||
noop:subject-a:d5318
|
||||
---- Noop failure -----
|
||||
No code was inserted. And the test did NOT PASS.
|
||||
This is typically a problem of your specs not passing unmutated.
|
||||
Test Result:
|
||||
- 1 @ runtime: 1.0
|
||||
- test-a
|
||||
Test Output:
|
||||
mutation b test result output
|
||||
-----------------------
|
||||
Mutant configuration:
|
||||
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
||||
Integration: null
|
||||
Expect Coverage: 100.00%
|
||||
Jobs: 1
|
||||
Includes: []
|
||||
Requires: []
|
||||
Subjects: 1
|
||||
Mutations: 2
|
||||
Kills: 0
|
||||
Alive: 2
|
||||
Runtime: 4.00s
|
||||
Killtime: 2.00s
|
||||
Overhead: 100.00%
|
||||
Coverage: 0.00%
|
||||
Expected: 100.00%
|
||||
REPORT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,4 +6,16 @@ RSpec.describe Mutant::Reporter::Trace do
|
|||
|
||||
it { should eql(0.0) }
|
||||
end
|
||||
|
||||
let(:reportable) { double('Reportable') }
|
||||
|
||||
%i[report start progress].each do |name|
|
||||
describe "##{name}" do
|
||||
subject { object.public_send(name, reportable) }
|
||||
|
||||
it 'logs the reportable' do
|
||||
expect { subject }.to change { object.public_send("#{name}_calls") }.from([]).to([reportable])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue