Class: Mutante::Reporter

Inherits:
Object
  • Object
show all
Defined in:
lib/mutante/reporter.rb

Constant Summary collapse

SPINNER_FRAMES =
%w[         ].freeze
COLORS =
{
  reset:   "\e[0m",
  bold:    "\e[1m",
  dim:     "\e[2m",
  red:     "\e[31m",
  green:   "\e[32m",
  yellow:  "\e[33m",
  blue:    "\e[34m",
  magenta: "\e[35m",
  cyan:    "\e[36m",
  gray:    "\e[90m"
}.freeze
CLEAR_LINE =
"\e[2K\r".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io: $stdout, force_plain: false, output_path: "mutante_uncovered.txt") ⇒ Reporter

Returns a new instance of Reporter.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/mutante/reporter.rb', line 20

def initialize(io: $stdout, force_plain: false, output_path: "mutante_uncovered.txt")
  @io            = io
  @flagged       = []
  @tty           = !force_plain && io.respond_to?(:tty?) && io.tty?
  @total_files   = 0
  @file_index    = 0
  @current_file  = nil
  @counts        = nil
  @file_started  = nil
  @started_at    = nil
  @spinner_index = 0
  @output_path   = output_path
  @total_source_lines = 0
  @total_eligible     = 0
  @mutex          = Mutex.new
  @spinner_thread = nil
end

Instance Attribute Details

#flaggedObject (readonly)

Returns the value of attribute flagged.



185
186
187
# File 'lib/mutante/reporter.rb', line 185

def flagged
  @flagged
end

Instance Method Details

#baseline_result(ok) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/mutante/reporter.rb', line 62

def baseline_result(ok)
  if @tty
    @io.print CLEAR_LINE
    if ok
      @io.puts "  #{color(:green)}#{color(:reset)} baseline #{color(:green)}green#{color(:reset)}"
    else
      @io.puts "  #{color(:red)}#{color(:reset)} baseline #{color(:red)}RED#{color(:reset)} — fix the suite before running mutante."
    end
  else
    @io.puts(ok ? "  baseline green." : "  baseline RED.")
    @io.puts
  end
end

#baseline_startingObject



52
53
54
55
56
57
58
59
60
# File 'lib/mutante/reporter.rb', line 52

def baseline_starting
  if @tty
    @io.puts
    @io.print "  #{color(:cyan)}#{color(:reset)} running baseline test suite..."
    @io.flush
  else
    @io.puts "mutante: running baseline test suite..."
  end
end

#file_finished(total_lines: nil) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/mutante/reporter.rb', line 140

def file_finished(total_lines: nil)
  stop_spinner_thread
  @mutex.synchronize do
    @total_source_lines += total_lines.to_i if total_lines
    @total_eligible     += @counts[:tested] if @counts

    if @tty
      @io.print CLEAR_LINE
      elapsed = format_duration(monotonic_now - (@file_started || monotonic_now))
      icon    = @counts && @counts[:flagged].positive? ? "#{color(:yellow)}#{color(:reset)}" : "#{color(:green)}#{color(:reset)}"
      parts   = []
      parts << "#{@counts[:tested]} tested" if @counts
      parts << "#{color(:red)}#{@counts[:flagged]} flagged#{color(:reset)}" if @counts && @counts[:flagged].positive?
      parts << "#{@counts[:skipped]} skipped" if @counts && @counts[:skipped].positive?
      parts << "#{color(:gray)}#{elapsed}#{color(:reset)}"
      @io.puts "  #{icon} #{parts.join(color(:gray) + ' · ' + color(:reset))}"
    else
      @io.puts
    end
  end
end

#file_starting(path) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/mutante/reporter.rb', line 76

def file_starting(path)
  @mutex.synchronize do
    @file_index  += 1
    @current_file = path
    @counts       = { tested: 0, flagged: 0, skipped: 0 }
    @file_started = monotonic_now

    if @tty
      @io.puts
      @io.puts "#{color(:cyan)}#{color(:reset)} " \
               "#{color(:bold)}#{path}#{color(:reset)} " \
               "#{color(:gray)}[#{@file_index}/#{@total_files}]#{color(:reset)}"
      redraw_status
    else
      @io.puts path
    end
  end
  start_spinner_thread
end

#finishedObject



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/mutante/reporter.rb', line 162

def finished
  stop_spinner_thread
  if @tty
    draw_summary
    draw_totals
  else
    @io.puts
    @io.puts "=" * 60
    if @flagged.empty?
      @io.puts "mutante: no dead-code candidates found."
    else
      plural = @flagged.size == 1 ? "candidate line" : "candidate lines"
      @io.puts "mutante: #{@flagged.size} #{plural} flagged:"
      @flagged.each do |entry|
        @io.puts "  #{entry[:path]}:#{entry[:line]}  #{entry[:text].strip}"
      end
    end
    print_totals_plain
  end

  write_uncovered_file
end

#line_flagged(path, line_number, line_text) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/mutante/reporter.rb', line 96

def line_flagged(path, line_number, line_text)
  @mutex.synchronize do
    @flagged << { path: path, line: line_number, text: line_text }
    @counts[:flagged] += 1 if @counts
    @counts[:tested]  += 1 if @counts

    if @tty
      @io.print CLEAR_LINE
      @io.puts "  #{color(:red)}#{color(:reset)} " \
               "#{color(:red)}#{path}:#{line_number}#{color(:reset)}  " \
               "#{color(:dim)}#{line_text.strip}#{color(:reset)}"
      redraw_status
    else
      @io.puts "  flagged #{path}:#{line_number}  #{line_text.strip}"
    end
  end
end

#line_safe(_path, _line_number) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/mutante/reporter.rb', line 114

def line_safe(_path, _line_number)
  @mutex.synchronize do
    @counts[:tested] += 1 if @counts

    if @tty
      redraw_status
    else
      @io.print "."
      @io.flush
    end
  end
end

#line_skipped(_path, _line_number, _reason) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/mutante/reporter.rb', line 127

def line_skipped(_path, _line_number, _reason)
  @mutex.synchronize do
    @counts[:skipped] += 1 if @counts

    if @tty
      redraw_status
    else
      @io.print "-"
      @io.flush
    end
  end
end

#starting(files) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/mutante/reporter.rb', line 38

def starting(files)
  @total_files = files.size
  @started_at  = monotonic_now
  plural       = files.size == 1 ? "file" : "files"
  subtitle     = "analyzing #{files.size} #{plural} · reverse mutation testing"

  if @tty
    draw_header("mutante v#{Mutante::VERSION}", subtitle)
  else
    @io.puts "mutante: #{subtitle}"
    @io.puts
  end
end