lib/mutant/reporter/cli/printer.rb in mutant-0.7.9 vs lib/mutant/reporter/cli/printer.rb in mutant-0.8.0

- old
+ new

@@ -1,29 +1,18 @@ module Mutant class Reporter 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] # # @api private @@ -65,11 +54,11 @@ # @return [undefined] # # @api private # def visit(printer, object) - printer.run(output, object) + printer.call(output, object) end # Print an info line to output # # @return [undefined] @@ -131,493 +120,9 @@ # @return [Boolean] # # @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) - info('Active subjects: %d', active_subject_results.length) - visit_collection(SubjectProgress, active_subject_results) - job_status - 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_tests - print_mutation_results - print_progress_bar_finish - print_stats - 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 end # Mutant