123456789_123456789_123456789_123456789_123456789_

Module: SimpleCov::CLI::Uncovered

Relationships & Source Files
Defined in: lib/simplecov/cli/uncovered.rb

Overview

simplecov uncovered [--threshold N] [--top N] [--criterion C] — list the lowest-coverage files (by the chosen criterion, ascending), so a developer can answer "where should I add tests next?" without opening a browser. Reads coverage.json directly.

Constant Summary

  • CRITERION_KEYS =

    The coverage.json fields backing each criterion.

    # File 'lib/simplecov/cli/uncovered.rb', line 17
    {
      line: {percent: "lines_covered_percent", covered: "covered_lines", total: "total_lines"},
      branch: {percent: "branches_covered_percent", covered: "covered_branches", total: "total_branches"},
      method: {percent: "methods_covered_percent", covered: "covered_methods", total: "total_methods"}
    }.freeze
  • DEFAULT_TOP =
    # File 'lib/simplecov/cli/uncovered.rb', line 14
    10

Class Method Summary

Class Method Details

.build_parser(opts) (mod_func)

Option parsing with per-flag coercions is inherently ABC-heavy; the metric is noise here.

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 60

def build_parser(opts) # rubocop:disable Metrics/AbcSize
  OptionParser.new do |o|
    o.on("--input PATH")         { |v| opts[:input] = v }
    o.on("--threshold N", Float) { |v| opts[:threshold] = v }
    o.on("--top N", Integer)     { |v| opts[:top] = v }
    o.on("--criterion C")        { |v| opts[:criterion] = v.to_sym }
    o.on("--json")               { opts[:json] = true }
    o.on("--no-color")           { opts[:no_color] = true }
  end
end

.emit(stdout, files, opts) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 48

def emit(stdout, files, opts)
  opts[:json] ? emit_json(stdout, files) : emit_text(stdout, files, SimpleCov::CLI.color_enabled?(opts, stdout))
end

.emit_json(stdout, files) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 75

def emit_json(stdout, files)
  rows = files.map do |fname, pct, covered, total|
    {"file" => fname, "percent" => pct, "covered" => covered, "total" => total}
  end
  stdout.puts(JSON.pretty_generate(rows))
end

.emit_text(stdout, files, color) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 71

def emit_text(stdout, files, color)
  files.each { |fname, pct, covered, total| stdout.puts(format_row(fname, pct, covered, total, color)) }
end

.empty_message(json) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 82

def empty_message(json)
  json ? "[]" : "simplecov uncovered: nothing to report"
end

.format_row(fname, pct, covered, total, color) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 100

def format_row(fname, pct, covered, total, color)
  format("%<pct>s  %<covered>d/%<total>d  %<fname>s",
         pct: SimpleCov::Color.colorize_percent(pct, format("%6.2f%%", pct), enabled: color),
         covered: covered, total: total, fname: fname)
end

.parse(args) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 52

def parse(args)
  opts = {input: SimpleCov::CLI.default_input, threshold: 100.0, top: DEFAULT_TOP, criterion: :line, no_color: false}
  build_parser(opts).parse(args)
  opts
end

.rank(coverage_hash, threshold, keys) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 86

def rank(coverage_hash, threshold, keys)
  rows = coverage_hash.filter_map { |fname, payload| row_for(fname, payload, threshold, keys) }
  rows.sort_by { |_fname, pct, _c, _t| pct }
end

.report(opts, keys, stdout, stderr) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 33

def report(opts, keys, stdout, stderr)
  return 1 unless (data = Report.load_data(opts[:input], stderr))

  files = rank(data.fetch("coverage", {}), opts[:threshold], keys).first(opts[:top])
  return stdout.puts(empty_message(opts[:json])) || 0 if files.empty?

  emit(stdout, files, opts)
  0
end

.row_for(fname, payload, threshold, keys) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 91

def row_for(fname, payload, threshold, keys)
  return unless payload.is_a?(Hash) && payload[keys[:total]].to_i.positive?

  pct = payload[keys[:percent]].to_f
  return if pct >= threshold

  [fname, pct, payload[keys[:covered]].to_i, payload[keys[:total]].to_i]
end

.run(args, stdout:, stderr:) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 25

def run(args, stdout:, stderr:, **)
  opts = parse(args)
  keys = CRITERION_KEYS[opts[:criterion]]
  return unknown_criterion(opts[:criterion], stderr) unless keys

  report(opts, keys, stdout, stderr)
end

.unknown_criterion(criterion, stderr) (mod_func)

[ GitHub ]

  
# File 'lib/simplecov/cli/uncovered.rb', line 43

def unknown_criterion(criterion, stderr)
  stderr.puts("simplecov uncovered: unknown --criterion #{criterion.inspect} (expected line, branch, or method)")
  1
end