minitest-heat 0.0.9 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/Gemfile.lock +6 -6
- data/README.md +49 -14
- data/examples/exceptions.png +0 -0
- data/examples/failures.png +0 -0
- data/examples/map.png +0 -0
- data/examples/markers.png +0 -0
- data/examples/skips.png +0 -0
- data/examples/slows.png +0 -0
- data/lib/minitest/heat/backtrace/line_parser.rb +25 -0
- data/lib/minitest/heat/backtrace.rb +39 -43
- data/lib/minitest/heat/hit.rb +36 -19
- data/lib/minitest/heat/issue.rb +118 -81
- data/lib/minitest/heat/location.rb +115 -116
- data/lib/minitest/heat/locations.rb +105 -0
- data/lib/minitest/heat/map.rb +16 -4
- data/lib/minitest/heat/output/backtrace.rb +90 -67
- data/lib/minitest/heat/output/issue.rb +76 -67
- data/lib/minitest/heat/output/map.rb +127 -25
- data/lib/minitest/heat/output/marker.rb +5 -3
- data/lib/minitest/heat/output/results.rb +3 -2
- data/lib/minitest/heat/output/source_code.rb +1 -1
- data/lib/minitest/heat/output/token.rb +2 -1
- data/lib/minitest/heat/output.rb +76 -6
- data/lib/minitest/heat/results.rb +23 -3
- data/lib/minitest/heat/source.rb +1 -1
- data/lib/minitest/heat/version.rb +1 -1
- data/lib/minitest/heat.rb +3 -2
- data/lib/minitest/heat_plugin.rb +9 -17
- data/lib/minitest/heat_reporter.rb +25 -35
- metadata +11 -4
- data/lib/minitest/heat/line.rb +0 -74
@@ -3,6 +3,7 @@
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
5
|
class Output
|
6
|
+
# Generates the tokens to output the resulting heat map
|
6
7
|
class Map
|
7
8
|
attr_accessor :results
|
8
9
|
|
@@ -12,16 +13,36 @@ module Minitest
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def tokens
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
results.heat_map.file_hits.each do |hit|
|
17
|
+
# Focus on the relevant issues based on most significant problems. i.e. If there are
|
18
|
+
# legitimate failures or errors, skips and slows aren't relevant
|
19
|
+
next unless relevant_issue_types?(hit)
|
18
20
|
|
19
|
-
|
21
|
+
# Add a new line
|
22
|
+
@tokens << [[:muted, ""]]
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
# Build the summary line for the file
|
25
|
+
@tokens << file_summary_tokens(hit)
|
26
|
+
|
27
|
+
# Get the set of line numbers that appear more than once
|
28
|
+
repeated_line_numbers = find_repeated_line_numbers_in(hit)
|
29
|
+
|
30
|
+
# Only display more details if the same line number shows up more than once
|
31
|
+
next unless repeated_line_numbers.any?
|
32
|
+
|
33
|
+
repeated_line_numbers.each do |line_number|
|
34
|
+
# Get the backtraces for the given line numbers
|
35
|
+
traces = hit.lines[line_number.to_s]
|
36
|
+
|
37
|
+
# If there aren't any traces there's no way to provide additional details
|
38
|
+
break unless traces.any?
|
39
|
+
|
40
|
+
# A short summary explaining the details that will follow
|
41
|
+
@tokens << [[:muted, " Issues on Line #{line_number} initially triggered from these locations:"]]
|
42
|
+
|
43
|
+
# The last relevant location for each error's backtrace
|
44
|
+
@tokens += origination_sources(traces)
|
45
|
+
end
|
25
46
|
end
|
26
47
|
|
27
48
|
@tokens
|
@@ -29,13 +50,41 @@ module Minitest
|
|
29
50
|
|
30
51
|
private
|
31
52
|
|
32
|
-
def
|
33
|
-
|
53
|
+
def origination_sources(traces)
|
54
|
+
# 1. Sort the traces by the most recent line number so they're displayed in numeric order
|
55
|
+
# 2. Get the final relevant location from the trace
|
56
|
+
traces.
|
57
|
+
sort_by { |trace| trace.locations.last.line_number }.
|
58
|
+
map { |trace| origination_location_token(trace) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def file_summary_tokens(hit)
|
62
|
+
pathname_tokens = pathname(hit)
|
63
|
+
line_number_list_tokens = sorted_line_number_list(hit)
|
64
|
+
|
65
|
+
[*pathname_tokens, *line_number_list_tokens]
|
66
|
+
end
|
67
|
+
|
68
|
+
def origination_location_token(trace)
|
69
|
+
# The earliest project line from the backtrace—this is probabyl wholly incorrect in terms
|
70
|
+
# of what would be the most helpful line to display, but it's a start.
|
71
|
+
location = trace.locations.last
|
72
|
+
|
73
|
+
[
|
74
|
+
[:muted, " #{Output::SYMBOLS[:arrow]} "],
|
75
|
+
[:default, location.relative_filename],
|
76
|
+
[:muted, ':'],
|
77
|
+
[:default, location.line_number],
|
78
|
+
[:muted, " in #{location.container}"],
|
79
|
+
[:muted, " #{Output::SYMBOLS[:arrow]} `#{location.source_code.line.strip}`"],
|
80
|
+
]
|
34
81
|
end
|
35
82
|
|
36
83
|
def relevant_issue_types
|
84
|
+
# These are always relevant.
|
37
85
|
issue_types = %i[error broken failure]
|
38
86
|
|
87
|
+
# These are only relevant if there aren't more serious isues.
|
39
88
|
issue_types << :skipped unless results.problems?
|
40
89
|
issue_types << :painful unless results.problems? || results.skips.any?
|
41
90
|
issue_types << :slow unless results.problems? || results.skips.any?
|
@@ -43,32 +92,85 @@ module Minitest
|
|
43
92
|
issue_types
|
44
93
|
end
|
45
94
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
95
|
+
def relevant_issue_types?(hit)
|
96
|
+
# The intersection of which issue types are relevant based on the context and which issues
|
97
|
+
# matc those issue types
|
98
|
+
intersection_issue_types = relevant_issue_types & hit.issues.keys
|
99
|
+
|
100
|
+
intersection_issue_types.any?
|
101
|
+
end
|
102
|
+
|
103
|
+
def find_repeated_line_numbers_in(hit)
|
104
|
+
repeated_line_numbers = []
|
105
|
+
|
106
|
+
hit.lines.each_pair do |line_number, traces|
|
107
|
+
# If there aren't multiple traces for a line number, it's not a repeat
|
108
|
+
next unless traces.size > 1
|
109
|
+
|
110
|
+
repeated_line_numbers << Integer(line_number)
|
111
|
+
end
|
112
|
+
|
113
|
+
repeated_line_numbers.sort
|
114
|
+
end
|
115
|
+
|
116
|
+
def pathname(hit)
|
117
|
+
directory = hit.pathname.dirname.to_s.delete_prefix("#{Dir.pwd}/")
|
118
|
+
filename = hit.pathname.basename.to_s
|
49
119
|
|
50
120
|
[
|
51
|
-
[:default, directory],
|
121
|
+
[:default, "#{directory}/"],
|
52
122
|
[:bold, filename],
|
53
123
|
[:default, ' · ']
|
54
124
|
]
|
55
125
|
end
|
56
126
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
127
|
+
# Gets the list of line numbers for a given hit location (i.e. file) so they can be
|
128
|
+
# displayed after the file name to show which lines were problematic
|
129
|
+
# @param hit [Hit] the instance to extract line numbers from
|
130
|
+
#
|
131
|
+
# @return [Array<Symbol,String>] [description]
|
132
|
+
def line_number_tokens_for_hit(hit)
|
133
|
+
line_number_tokens = []
|
134
|
+
|
135
|
+
relevant_issue_types.each do |issue_type|
|
136
|
+
# Retrieve any line numbers for the issue type
|
137
|
+
line_numbers_for_issue_type = hit.issues.fetch(issue_type) { [] }
|
138
|
+
|
139
|
+
# Build the list of tokens representing styled line numbers
|
140
|
+
line_numbers_for_issue_type.each do |line_number|
|
141
|
+
line_number_tokens << line_number_token(issue_type, line_number)
|
142
|
+
end
|
62
143
|
end
|
63
|
-
|
144
|
+
|
145
|
+
line_number_tokens.compact
|
64
146
|
end
|
65
147
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
148
|
+
# Builds a token representing a styled line number
|
149
|
+
#
|
150
|
+
# @param style [Symbol] the relevant display style for the issue
|
151
|
+
# @param line_number [Integer] the affected line number
|
152
|
+
#
|
153
|
+
# @return [Array<Symbol,Integer>] array token representing the line number and issue type
|
154
|
+
def line_number_token(style, line_number)
|
155
|
+
[style, "#{line_number} "]
|
156
|
+
end
|
157
|
+
|
158
|
+
# Sorts line number tokens so that line numbers are displayed in order regardless of their
|
159
|
+
# underlying issue type
|
160
|
+
#
|
161
|
+
# @param hit [Hit] the instance of the hit file details to build the heat map entry
|
162
|
+
#
|
163
|
+
# @return [Array] the arrays representing the line number tokens to display next to a file
|
164
|
+
# name in the heat map. ex [[:error, 12], [:falure, 13]]
|
165
|
+
def sorted_line_number_list(hit)
|
166
|
+
# Sort the collected group of line number hits so they're in order
|
167
|
+
line_number_tokens_for_hit(hit).sort do |a, b|
|
168
|
+
# Ensure the line numbers are integers for sorting (otherwise '100' comes before '12')
|
169
|
+
first_line_number = Integer(a[1].strip)
|
170
|
+
second_line_number = Integer(b[1].strip)
|
171
|
+
|
172
|
+
first_line_number <=> second_line_number
|
70
173
|
end
|
71
|
-
line_number_tokens.compact.sort_by { |number_token| number_token[1] }
|
72
174
|
end
|
73
175
|
end
|
74
176
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
|
-
# Friendly API for printing nicely-formatted output to the console
|
6
5
|
class Output
|
6
|
+
# Friendly API for printing consistent markers for the various issue types
|
7
7
|
class Marker
|
8
8
|
SYMBOLS = {
|
9
9
|
success: '·',
|
@@ -12,7 +12,8 @@ module Minitest
|
|
12
12
|
broken: 'B',
|
13
13
|
error: 'E',
|
14
14
|
skipped: 'S',
|
15
|
-
failure: 'F'
|
15
|
+
failure: 'F',
|
16
|
+
reporter: '✖'
|
16
17
|
}.freeze
|
17
18
|
|
18
19
|
STYLES = {
|
@@ -22,7 +23,8 @@ module Minitest
|
|
22
23
|
broken: :error,
|
23
24
|
error: :error,
|
24
25
|
skipped: :skipped,
|
25
|
-
failure: :failure
|
26
|
+
failure: :failure,
|
27
|
+
reporter: :error
|
26
28
|
}.freeze
|
27
29
|
|
28
30
|
attr_accessor :issue_type
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
5
|
class Output
|
6
|
+
# Generates the output tokens to display the results summary
|
6
7
|
class Results
|
7
8
|
extend Forwardable
|
8
9
|
|
@@ -90,7 +91,7 @@ module Minitest
|
|
90
91
|
end
|
91
92
|
|
92
93
|
def test_count_token
|
93
|
-
[:default,
|
94
|
+
[:default, pluralize(timer.test_count, 'test').to_s]
|
94
95
|
end
|
95
96
|
|
96
97
|
def tests_performance_token
|
@@ -98,7 +99,7 @@ module Minitest
|
|
98
99
|
end
|
99
100
|
|
100
101
|
def assertions_count_token
|
101
|
-
[:default,
|
102
|
+
[:default, pluralize(timer.assertion_count, 'assertion').to_s]
|
102
103
|
end
|
103
104
|
|
104
105
|
def assertions_performance_token
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
5
|
class Output
|
6
|
-
#
|
6
|
+
# Generates the tokens representing a specific set of source code lines
|
7
7
|
class SourceCode
|
8
8
|
DEFAULT_LINE_COUNT = 3
|
9
9
|
DEFAULT_INDENTATION_SPACES = 2
|
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
|
-
# Friendly API for printing nicely-formatted output to the console
|
6
5
|
class Output
|
6
|
+
# Provides a convenient interface for creating console-friendly output while ensuring
|
7
|
+
# consistency in the applied styles.
|
7
8
|
class Token
|
8
9
|
class InvalidStyle < ArgumentError; end
|
9
10
|
|
data/lib/minitest/heat/output.rb
CHANGED
@@ -11,18 +11,18 @@ require_relative 'output/token'
|
|
11
11
|
module Minitest
|
12
12
|
module Heat
|
13
13
|
# Friendly API for printing nicely-formatted output to the console
|
14
|
-
class Output
|
14
|
+
class Output # rubocop:disable Metrics/ClassLength
|
15
15
|
SYMBOLS = {
|
16
16
|
middot: '·',
|
17
17
|
arrow: '➜',
|
18
|
-
lead: '|'
|
18
|
+
lead: '|'
|
19
19
|
}.freeze
|
20
20
|
|
21
21
|
TOKENS = {
|
22
|
-
spacer:
|
22
|
+
spacer: [:muted, " #{SYMBOLS[:middot]} "],
|
23
23
|
muted_arrow: [:muted, " #{SYMBOLS[:arrow]} "],
|
24
|
-
muted_lead:
|
25
|
-
}
|
24
|
+
muted_lead: [:muted, "#{SYMBOLS[:lead]} "]
|
25
|
+
}.freeze
|
26
26
|
|
27
27
|
attr_reader :stream
|
28
28
|
|
@@ -42,8 +42,33 @@ module Minitest
|
|
42
42
|
end
|
43
43
|
alias newline puts
|
44
44
|
|
45
|
+
def issues_list(results)
|
46
|
+
# A couple of blank lines to create some breathing room
|
47
|
+
newline
|
48
|
+
newline
|
49
|
+
|
50
|
+
# Issues start with the least critical and go up to the most critical so that the most
|
51
|
+
# pressing issues are displayed at the bottom of the report in order to reduce scrolling.
|
52
|
+
#
|
53
|
+
# This way, as you fix issues, the list gets shorter, and eventually the least critical
|
54
|
+
# issues will be displayed without scrolling once more problematic issues are resolved.
|
55
|
+
%i[slows painfuls skips failures brokens errors].each do |issue_category|
|
56
|
+
# Only show categories for the most pressing issues after the suite runs, otherwise,
|
57
|
+
# suppress them until the more critical issues are resolved.
|
58
|
+
next unless show?(issue_category, results)
|
59
|
+
|
60
|
+
results.send(issue_category).each { |issue| issue_details(issue) }
|
61
|
+
end
|
62
|
+
rescue StandardError => e
|
63
|
+
message = "Sorry, but Minitest Heat couldn't display the details of any failures."
|
64
|
+
exception_guidance(message, e)
|
65
|
+
end
|
66
|
+
|
45
67
|
def issue_details(issue)
|
46
68
|
print_tokens Minitest::Heat::Output::Issue.new(issue).tokens
|
69
|
+
rescue StandardError => e
|
70
|
+
message = "Sorry, but Minitest Heat couldn't display output for a specific failure."
|
71
|
+
exception_guidance(message, e)
|
47
72
|
end
|
48
73
|
|
49
74
|
def marker(issue_type)
|
@@ -53,15 +78,56 @@ module Minitest
|
|
53
78
|
def compact_summary(results, timer)
|
54
79
|
newline
|
55
80
|
print_tokens ::Minitest::Heat::Output::Results.new(results, timer).tokens
|
81
|
+
rescue StandardError => e
|
82
|
+
message = "Sorry, but Minitest Heat couldn't display the summary."
|
83
|
+
exception_guidance(message, e)
|
56
84
|
end
|
57
85
|
|
58
86
|
def heat_map(map)
|
59
87
|
newline
|
60
88
|
print_tokens ::Minitest::Heat::Output::Map.new(map).tokens
|
89
|
+
newline
|
90
|
+
rescue StandardError => e
|
91
|
+
message = "Sorry, but Minitest Heat couldn't display the heat map."
|
92
|
+
exception_guidance(message, e)
|
61
93
|
end
|
62
94
|
|
63
95
|
private
|
64
96
|
|
97
|
+
# Displays some guidance related to exceptions generated by Minitest Heat in order to help
|
98
|
+
# people get back on track (and ideally submit issues)
|
99
|
+
# @param message [String] a slightly more specific explanation of which part of minitest-heat
|
100
|
+
# caused the failure
|
101
|
+
# @param exception [Exception] the exception that caused the problem
|
102
|
+
#
|
103
|
+
# @return [void] displays the guidance to the console
|
104
|
+
def exception_guidance(message, exception)
|
105
|
+
newline
|
106
|
+
puts "#{message} Disabling Minitest Heat can get you back on track until the problem can be fixed."
|
107
|
+
puts 'Please use the following exception details to submit an issue at https://github.com/garrettdimon/minitest-heat/issues'
|
108
|
+
puts "#{exception.message}:"
|
109
|
+
exception.backtrace.each do |line|
|
110
|
+
puts " #{line}"
|
111
|
+
end
|
112
|
+
newline
|
113
|
+
end
|
114
|
+
|
115
|
+
def no_problems?(results)
|
116
|
+
!results.problems?
|
117
|
+
end
|
118
|
+
|
119
|
+
def no_problems_or_skips?(results)
|
120
|
+
!results.problems? && results.skips.none?
|
121
|
+
end
|
122
|
+
|
123
|
+
def show?(issue_category, results)
|
124
|
+
case issue_category
|
125
|
+
when :skips then no_problems?(results)
|
126
|
+
when :painfuls, :slows then no_problems_or_skips?(results)
|
127
|
+
else true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
65
131
|
def style_enabled?
|
66
132
|
stream.tty?
|
67
133
|
end
|
@@ -82,7 +148,11 @@ module Minitest
|
|
82
148
|
def print_tokens(lines_of_tokens)
|
83
149
|
lines_of_tokens.each do |tokens|
|
84
150
|
tokens.each do |token|
|
85
|
-
|
151
|
+
begin
|
152
|
+
print Token.new(*token).to_s(token_format)
|
153
|
+
rescue
|
154
|
+
puts token.inspect
|
155
|
+
end
|
86
156
|
end
|
87
157
|
newline
|
88
158
|
end
|
@@ -11,9 +11,29 @@ module Minitest
|
|
11
11
|
@heat_map = Heat::Map.new
|
12
12
|
end
|
13
13
|
|
14
|
+
# Logs an issue to the results for later reporting
|
15
|
+
# @param issue [Issue] the issue generated from a given test result
|
16
|
+
#
|
17
|
+
# @return [type] [description]
|
14
18
|
def record(issue)
|
19
|
+
# Record everything—even if it's a success
|
15
20
|
@issues.push(issue)
|
16
|
-
|
21
|
+
|
22
|
+
# If it's not a genuine problem, we're done here...
|
23
|
+
return unless issue.hit?
|
24
|
+
|
25
|
+
# ...otherwise update the heat map
|
26
|
+
update_heat_map(issue)
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_heat_map(issue)
|
30
|
+
# For heat map purposes, only the project backtrace lines are interesting
|
31
|
+
pathname, line_number = issue.locations.project.to_a
|
32
|
+
|
33
|
+
# Backtrace is only relevant for exception-generating issues, not slows, skips, or failures
|
34
|
+
backtrace = issue.error? ? issue.locations.backtrace.project_locations : []
|
35
|
+
|
36
|
+
@heat_map.add(pathname, line_number, issue.type, backtrace: backtrace)
|
17
37
|
end
|
18
38
|
|
19
39
|
def problems?
|
@@ -37,11 +57,11 @@ module Minitest
|
|
37
57
|
end
|
38
58
|
|
39
59
|
def painfuls
|
40
|
-
@painfuls ||= select_issues(:painful).sort_by(&:
|
60
|
+
@painfuls ||= select_issues(:painful).sort_by(&:execution_time).reverse
|
41
61
|
end
|
42
62
|
|
43
63
|
def slows
|
44
|
-
@slows ||= select_issues(:slow).sort_by(&:
|
64
|
+
@slows ||= select_issues(:slow).sort_by(&:execution_time).reverse
|
45
65
|
end
|
46
66
|
|
47
67
|
private
|
data/lib/minitest/heat/source.rb
CHANGED
data/lib/minitest/heat.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
require_relative 'heat/backtrace'
|
4
4
|
require_relative 'heat/hit'
|
5
5
|
require_relative 'heat/issue'
|
6
|
-
require_relative 'heat/line'
|
7
6
|
require_relative 'heat/location'
|
7
|
+
require_relative 'heat/locations'
|
8
8
|
require_relative 'heat/map'
|
9
9
|
require_relative 'heat/output'
|
10
10
|
require_relative 'heat/results'
|
@@ -13,7 +13,8 @@ require_relative 'heat/timer'
|
|
13
13
|
require_relative 'heat/version'
|
14
14
|
|
15
15
|
module Minitest
|
16
|
-
# Custom
|
16
|
+
# Custom Minitest reporter focused on generating output designed around efficiently identifying
|
17
|
+
# issues and potential solutions
|
17
18
|
# - Colorize the Output
|
18
19
|
# - What files had the most errors?
|
19
20
|
# - Show the most impacted areas first.
|
data/lib/minitest/heat_plugin.rb
CHANGED
@@ -2,25 +2,17 @@
|
|
2
2
|
|
3
3
|
require_relative 'heat_reporter'
|
4
4
|
|
5
|
-
module Minitest
|
6
|
-
def self.plugin_heat_options(opts, _options)
|
7
|
-
opts.on '--show-fast', 'Show failures as they happen instead of waiting for the entire suite.' do
|
8
|
-
# Heat.show_fast!
|
9
|
-
end
|
10
|
-
|
11
|
-
# TODO: options.
|
12
|
-
# 1. Fail Fast
|
13
|
-
# 2. Don't worry about skips.
|
14
|
-
# 3. Skip coverage.
|
15
|
-
end
|
16
|
-
|
5
|
+
module Minitest # rubocop:disable Style/Documentation
|
17
6
|
def self.plugin_heat_init(options)
|
18
|
-
io = options
|
7
|
+
io = options.fetch(:io, $stdout)
|
19
8
|
|
20
|
-
|
21
|
-
|
9
|
+
reporter.reporters.reject! do |reporter|
|
10
|
+
# Minitest Heat acts as a unified Progress *and* Summary reporter. Using other reporters of
|
11
|
+
# those types in conjunction with it creates some overly-verbose output
|
12
|
+
reporter.is_a?(ProgressReporter) || reporter.is_a?(SummaryReporter)
|
13
|
+
end
|
22
14
|
|
23
|
-
#
|
24
|
-
reporter << HeatReporter.new(io, options)
|
15
|
+
# Hook up Reviewer
|
16
|
+
self.reporter.reporters << HeatReporter.new(io, options)
|
25
17
|
end
|
26
18
|
end
|
@@ -35,6 +35,8 @@ module Minitest
|
|
35
35
|
:results
|
36
36
|
|
37
37
|
def initialize(io = $stdout, options = {})
|
38
|
+
super()
|
39
|
+
|
38
40
|
@options = options
|
39
41
|
|
40
42
|
@timer = Heat::Timer.new
|
@@ -62,33 +64,39 @@ module Minitest
|
|
62
64
|
def record(result)
|
63
65
|
# Convert a Minitest Result into an "issue" to more consistently expose the data needed to
|
64
66
|
# adjust the failure output to the type of failure
|
65
|
-
issue = Heat::Issue.
|
67
|
+
issue = Heat::Issue.from_result(result)
|
68
|
+
|
69
|
+
# Note the number of assertions for the performance summary
|
70
|
+
timer.increment_counts(issue.assertions)
|
66
71
|
|
67
|
-
|
72
|
+
# Record the issue to show details later
|
68
73
|
results.record(issue)
|
69
74
|
|
75
|
+
# Show the marker
|
70
76
|
output.marker(issue.type)
|
77
|
+
rescue StandardError => e
|
78
|
+
display_exception_guidance(e)
|
71
79
|
end
|
72
80
|
|
73
|
-
|
74
|
-
def report
|
75
|
-
timer.stop!
|
76
|
-
|
77
|
-
# A couple of blank lines to create some breathing room
|
81
|
+
def display_exception_guidance(exception)
|
78
82
|
output.newline
|
83
|
+
puts 'Sorry, but Minitest Heat encountered an exception recording an issue. Disabling Minitest Heat will get you back on track.'
|
84
|
+
puts 'Please use the following exception details to submit an issue at https://github.com/garrettdimon/minitest-heat/issues'
|
85
|
+
puts "#{exception.message}:"
|
86
|
+
exception.backtrace.each do |line|
|
87
|
+
puts " #{line}"
|
88
|
+
end
|
79
89
|
output.newline
|
90
|
+
end
|
80
91
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# issues will be displayed without scrolling once more problematic issues are resolved.
|
85
|
-
%i[slows painfuls skips failures brokens errors].each do |issue_category|
|
86
|
-
next unless show?(issue_category)
|
92
|
+
# Outputs the summary of the run.
|
93
|
+
def report
|
94
|
+
timer.stop!
|
87
95
|
|
88
|
-
|
89
|
-
|
96
|
+
# The list of individual issues and their associated details
|
97
|
+
output.issues_list(results)
|
90
98
|
|
91
|
-
# Display a short summary of the total issue counts
|
99
|
+
# Display a short summary of the total issue counts for each category as well as performance
|
92
100
|
# details for the test suite as a whole
|
93
101
|
output.compact_summary(results, timer)
|
94
102
|
|
@@ -96,7 +104,7 @@ module Minitest
|
|
96
104
|
# common sources of issues
|
97
105
|
output.heat_map(results)
|
98
106
|
|
99
|
-
|
107
|
+
output.newline
|
100
108
|
output.newline
|
101
109
|
end
|
102
110
|
|
@@ -104,23 +112,5 @@ module Minitest
|
|
104
112
|
def passed?
|
105
113
|
results.errors.empty? && results.failures.empty?
|
106
114
|
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
def no_problems?
|
111
|
-
!results.problems?
|
112
|
-
end
|
113
|
-
|
114
|
-
def no_problems_or_skips?
|
115
|
-
!results.problems? && !results.skips.any?
|
116
|
-
end
|
117
|
-
|
118
|
-
def show?(issue_category)
|
119
|
-
case issue_category
|
120
|
-
when :skips then no_problems?
|
121
|
-
when :painfuls, :slows then no_problems_or_skips?
|
122
|
-
else true
|
123
|
-
end
|
124
|
-
end
|
125
115
|
end
|
126
116
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minitest-heat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Garrett Dimon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -141,12 +141,19 @@ files:
|
|
141
141
|
- Rakefile
|
142
142
|
- bin/console
|
143
143
|
- bin/setup
|
144
|
+
- examples/exceptions.png
|
145
|
+
- examples/failures.png
|
146
|
+
- examples/map.png
|
147
|
+
- examples/markers.png
|
148
|
+
- examples/skips.png
|
149
|
+
- examples/slows.png
|
144
150
|
- lib/minitest/heat.rb
|
145
151
|
- lib/minitest/heat/backtrace.rb
|
152
|
+
- lib/minitest/heat/backtrace/line_parser.rb
|
146
153
|
- lib/minitest/heat/hit.rb
|
147
154
|
- lib/minitest/heat/issue.rb
|
148
|
-
- lib/minitest/heat/line.rb
|
149
155
|
- lib/minitest/heat/location.rb
|
156
|
+
- lib/minitest/heat/locations.rb
|
150
157
|
- lib/minitest/heat/map.rb
|
151
158
|
- lib/minitest/heat/output.rb
|
152
159
|
- lib/minitest/heat/output/backtrace.rb
|
@@ -188,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
195
|
- !ruby/object:Gem::Version
|
189
196
|
version: '0'
|
190
197
|
requirements: []
|
191
|
-
rubygems_version: 3.
|
198
|
+
rubygems_version: 3.2.22
|
192
199
|
signing_key:
|
193
200
|
specification_version: 4
|
194
201
|
summary: Presents test results in a visual manner to guide you to where to look first.
|