minitest-heat 0.0.8 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/Gemfile.lock +6 -6
- data/README.md +1 -1
- 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 +98 -79
- 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 +52 -44
- data/lib/minitest/heat/output/issue.rb +65 -62
- data/lib/minitest/heat/output/map.rb +99 -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 +66 -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 +24 -34
- metadata +5 -4
- data/lib/minitest/heat/line.rb +0 -74
@@ -3,11 +3,13 @@
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
5
|
class Output
|
6
|
-
|
7
|
-
|
6
|
+
# Formats issues to output based on the issue type
|
7
|
+
class Issue # rubocop:disable Metrics/ClassLength
|
8
|
+
attr_accessor :issue, :locations
|
8
9
|
|
9
10
|
def initialize(issue)
|
10
11
|
@issue = issue
|
12
|
+
@locations = issue.locations
|
11
13
|
end
|
12
14
|
|
13
15
|
def tokens
|
@@ -27,7 +29,6 @@ module Minitest
|
|
27
29
|
[
|
28
30
|
headline_tokens,
|
29
31
|
test_location_tokens,
|
30
|
-
location_tokens,
|
31
32
|
summary_tokens,
|
32
33
|
*backtrace_tokens,
|
33
34
|
newline_tokens
|
@@ -78,93 +79,96 @@ module Minitest
|
|
78
79
|
end
|
79
80
|
|
80
81
|
def headline_tokens
|
81
|
-
[
|
82
|
+
[label_token(issue), spacer_token, [:default, test_name(issue)]]
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_name(issue)
|
86
|
+
test_prefix = 'test_'
|
87
|
+
identifier = issue.test_identifier
|
88
|
+
|
89
|
+
if identifier.start_with?(test_prefix)
|
90
|
+
identifier.delete_prefix(test_prefix).gsub('_', ' ').capitalize
|
91
|
+
else
|
92
|
+
identifier
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def label_token(issue)
|
97
|
+
[issue.type, issue_label(issue.type)]
|
98
|
+
end
|
99
|
+
|
100
|
+
def issue_label(issue_type)
|
101
|
+
case issue_type
|
102
|
+
when :error then 'Error'
|
103
|
+
when :broken then 'Broken Test'
|
104
|
+
when :failure then 'Failure'
|
105
|
+
when :skipped then 'Skipped'
|
106
|
+
when :slow then 'Passed but Slow'
|
107
|
+
when :painful then 'Passed but Very Slow'
|
108
|
+
when :passed then 'Success'
|
109
|
+
else 'Unknown'
|
110
|
+
end
|
82
111
|
end
|
83
112
|
|
84
113
|
def test_name_and_class_tokens
|
85
|
-
[[:default, issue.test_class], *test_location_tokens
|
114
|
+
[[:default, issue.test_class], *test_location_tokens]
|
86
115
|
end
|
87
116
|
|
88
117
|
def backtrace_tokens
|
89
|
-
|
90
|
-
|
91
|
-
backtrace.tokens
|
118
|
+
@backtrace_tokens ||= ::Minitest::Heat::Output::Backtrace.new(locations).tokens
|
92
119
|
end
|
93
120
|
|
94
121
|
def test_location_tokens
|
95
|
-
[
|
122
|
+
[
|
123
|
+
[:default, locations.test_definition.relative_filename],
|
124
|
+
[:muted, ':'],
|
125
|
+
[:default, locations.test_definition.line_number],
|
126
|
+
arrow_token,
|
127
|
+
[:default, locations.test_failure.line_number],
|
128
|
+
[:muted, "\n #{locations.test_failure.source_code.line.strip}"]
|
129
|
+
]
|
96
130
|
end
|
97
131
|
|
98
132
|
def location_tokens
|
99
|
-
[
|
133
|
+
[
|
134
|
+
[:default, locations.most_relevant.relative_filename],
|
135
|
+
[:muted, ':'],
|
136
|
+
[:default, locations.most_relevant.line_number],
|
137
|
+
[:muted, "\n #{locations.most_relevant.source_code.line.strip}"]
|
138
|
+
]
|
100
139
|
end
|
101
140
|
|
102
141
|
def source_tokens
|
103
|
-
filename =
|
104
|
-
line_number =
|
105
|
-
|
106
|
-
# source_code = ::Minitest::Heat::Output::SourceCode.new(filename, line_number, max_line_count: 1)
|
107
|
-
# source_code.tokens
|
108
|
-
|
142
|
+
filename = locations.project.filename
|
143
|
+
line_number = locations.project.line_number
|
109
144
|
source = Minitest::Heat::Source.new(filename, line_number: line_number)
|
145
|
+
|
110
146
|
[[:muted, " #{Output::SYMBOLS[:arrow]} `#{source.line.strip}`"]]
|
111
147
|
end
|
112
148
|
|
113
149
|
def summary_tokens
|
114
|
-
[[:italicized, issue.summary.delete_suffix(
|
150
|
+
[[:italicized, issue.summary.delete_suffix('---------------').strip]]
|
115
151
|
end
|
116
152
|
|
117
153
|
def slowness_summary_tokens
|
118
|
-
[
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
issue.location.most_relevant_file.to_s.delete_prefix("#{Dir.pwd}/")
|
127
|
-
end
|
128
|
-
|
129
|
-
def test_file_short_location
|
130
|
-
issue.location.test_file.to_s.delete_prefix("#{Dir.pwd}/")
|
154
|
+
[
|
155
|
+
[:bold, slowness(issue)],
|
156
|
+
spacer_token,
|
157
|
+
[:default, locations.test_definition.relative_path],
|
158
|
+
[:default, locations.test_definition.filename],
|
159
|
+
[:muted, ':'],
|
160
|
+
[:default, locations.test_definition.line_number]
|
161
|
+
]
|
131
162
|
end
|
132
163
|
|
133
|
-
def
|
134
|
-
|
135
|
-
line_number = issue.location.project_failure_line
|
136
|
-
|
137
|
-
source = Minitest::Heat::Source.new(filename, line_number: line_number)
|
138
|
-
"\n #{source.line.strip}"
|
164
|
+
def slowness(issue)
|
165
|
+
"#{issue.execution_time.round(2)}s"
|
139
166
|
end
|
140
167
|
|
141
|
-
def
|
142
|
-
|
143
|
-
line_number = issue.location.test_failure_line
|
144
|
-
|
145
|
-
source = Minitest::Heat::Source.new(filename, line_number: line_number)
|
146
|
-
"\n #{source.line.strip}"
|
168
|
+
def newline_tokens
|
169
|
+
[]
|
147
170
|
end
|
148
171
|
|
149
|
-
|
150
|
-
# def failure_summary_tokens
|
151
|
-
# return unless issue_summary_lines.any?
|
152
|
-
|
153
|
-
# # Sometimes, the exception message is multiple lines, so this adjusts the lines to
|
154
|
-
# # visually group them together a bit
|
155
|
-
# if issue_summary_lines.one?
|
156
|
-
# [[[:italicized, issue_summary_lines.first]]]
|
157
|
-
# else
|
158
|
-
# issue_summary_lines.map do |line|
|
159
|
-
# [Output::TOKENS[:muted_lead], [:italicized, line]]
|
160
|
-
# end
|
161
|
-
# end
|
162
|
-
# end
|
163
|
-
|
164
|
-
# def issue_summary_lines
|
165
|
-
# @issue_summary_lines ||= issue.summary.split("\n")
|
166
|
-
# end
|
167
|
-
|
168
172
|
def spacer_token
|
169
173
|
Output::TOKENS[:spacer]
|
170
174
|
end
|
@@ -172,7 +176,6 @@ module Minitest
|
|
172
176
|
def arrow_token
|
173
177
|
Output::TOKENS[:muted_arrow]
|
174
178
|
end
|
175
|
-
|
176
179
|
end
|
177
180
|
end
|
178
181
|
end
|
@@ -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,26 @@ module Minitest
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def tokens
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
results.heat_map.file_hits.each do |hit|
|
17
|
+
# If there's legitimate failures or errors, skips and slows aren't relevant
|
18
|
+
next unless relevant_issue_types?(hit)
|
18
19
|
|
19
|
-
|
20
|
+
@tokens << [[:muted, ""]]
|
21
|
+
@tokens << file_summary_tokens(hit)
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
repeats = repeated_line_numbers(hit)
|
24
|
+
next unless repeats.any?
|
25
|
+
|
26
|
+
repeats.each do |line_number|
|
27
|
+
@tokens << [[:muted, " Issues on Line #{line_number} initially triggered from these locations:"]]
|
28
|
+
|
29
|
+
traces = hit.lines[line_number.to_s]
|
30
|
+
sorted_traces = traces.sort_by { |trace| trace.locations.last.line_number }
|
31
|
+
|
32
|
+
sorted_traces.each do |trace|
|
33
|
+
@tokens << origination_location_token(trace)
|
34
|
+
end
|
35
|
+
end
|
25
36
|
end
|
26
37
|
|
27
38
|
@tokens
|
@@ -29,13 +40,33 @@ module Minitest
|
|
29
40
|
|
30
41
|
private
|
31
42
|
|
32
|
-
def
|
33
|
-
|
43
|
+
def file_summary_tokens(hit)
|
44
|
+
pathname_tokens = pathname(hit)
|
45
|
+
line_number_list_tokens = sorted_line_number_list(hit)
|
46
|
+
|
47
|
+
[*pathname_tokens, *line_number_list_tokens]
|
48
|
+
end
|
49
|
+
|
50
|
+
def origination_location_token(trace)
|
51
|
+
# The earliest project line from the backtrace—this is probabyl wholly incorrect in terms
|
52
|
+
# of what would be the most helpful line to display, but it's a start.
|
53
|
+
location = trace.locations.last
|
54
|
+
|
55
|
+
[
|
56
|
+
[:muted, " #{Output::SYMBOLS[:arrow]} "],
|
57
|
+
[:default, location.relative_filename],
|
58
|
+
[:muted, ':'],
|
59
|
+
[:default, location.line_number],
|
60
|
+
[:muted, " in #{location.container}"],
|
61
|
+
[:muted, " #{Output::SYMBOLS[:arrow]} `#{location.source_code.line.strip}`"],
|
62
|
+
]
|
34
63
|
end
|
35
64
|
|
36
65
|
def relevant_issue_types
|
66
|
+
# These are always relevant.
|
37
67
|
issue_types = %i[error broken failure]
|
38
68
|
|
69
|
+
# These are only relevant if there aren't more serious isues.
|
39
70
|
issue_types << :skipped unless results.problems?
|
40
71
|
issue_types << :painful unless results.problems? || results.skips.any?
|
41
72
|
issue_types << :slow unless results.problems? || results.skips.any?
|
@@ -43,32 +74,75 @@ module Minitest
|
|
43
74
|
issue_types
|
44
75
|
end
|
45
76
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
77
|
+
def relevant_issue_types?(hit)
|
78
|
+
intersection_issue_types = relevant_issue_types & hit.issues.keys
|
79
|
+
|
80
|
+
intersection_issue_types.any?
|
81
|
+
end
|
82
|
+
|
83
|
+
def repeated_line_numbers(hit)
|
84
|
+
repeated_line_numbers = []
|
85
|
+
|
86
|
+
hit.lines.each_pair do |line_number, traces|
|
87
|
+
# If there aren't multiple traces for a line number, it's not a repeat, right?
|
88
|
+
next unless traces.size > 1
|
89
|
+
|
90
|
+
repeated_line_numbers << Integer(line_number)
|
91
|
+
end
|
92
|
+
|
93
|
+
repeated_line_numbers.sort
|
94
|
+
end
|
95
|
+
|
96
|
+
def repeated_line_numbers?(hit)
|
97
|
+
repeated_line_numbers(hit).any?
|
98
|
+
end
|
99
|
+
|
100
|
+
def pathname(hit)
|
101
|
+
directory = hit.pathname.dirname.to_s.delete_prefix("#{Dir.pwd}/")
|
102
|
+
filename = hit.pathname.basename.to_s
|
49
103
|
|
50
104
|
[
|
51
|
-
[:default, directory],
|
105
|
+
[:default, "#{directory}/"],
|
52
106
|
[:bold, filename],
|
53
107
|
[:default, ' · ']
|
54
108
|
]
|
55
109
|
end
|
56
110
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
numbers
|
111
|
+
def line_number_tokens_for_hit(hit)
|
112
|
+
line_number_tokens = []
|
113
|
+
|
114
|
+
relevant_issue_types.each do |issue_type|
|
115
|
+
# Retrieve any line numbers for the issue type
|
116
|
+
line_numbers_for_issue_type = hit.issues.fetch(issue_type) { [] }
|
117
|
+
|
118
|
+
# Build the list of tokens representing styled line numbers
|
119
|
+
line_numbers_for_issue_type.each do |line_number|
|
120
|
+
line_number_tokens << line_number_token(issue_type, line_number)
|
121
|
+
end
|
62
122
|
end
|
63
|
-
|
123
|
+
|
124
|
+
line_number_tokens.compact
|
64
125
|
end
|
65
126
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
127
|
+
def line_number_token(style, line_number)
|
128
|
+
[style, "#{line_number} "]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Generates the line number tokens styled based on their error type
|
132
|
+
#
|
133
|
+
# @param [Hit] hit the instance of the hit file details to build the heat map entry
|
134
|
+
#
|
135
|
+
# @return [Array] the arrays representing the line number tokens to display next to a file
|
136
|
+
# name in the heat map
|
137
|
+
def sorted_line_number_list(hit)
|
138
|
+
# Sort the collected group of line number hits so they're in order
|
139
|
+
line_number_tokens_for_hit(hit).sort do |a, b|
|
140
|
+
# Ensure the line numbers are integers for sorting (otherwise '100' comes before '12')
|
141
|
+
first_line_number = Integer(a[1].strip)
|
142
|
+
second_line_number = Integer(b[1].strip)
|
143
|
+
|
144
|
+
first_line_number <=> second_line_number
|
70
145
|
end
|
71
|
-
line_number_tokens.compact.sort_by { |number_token| number_token[1] }
|
72
146
|
end
|
73
147
|
end
|
74
148
|
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,30 @@ 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
|
+
# This way, as you fix issues, the list gets shorter, and eventually the least critical
|
53
|
+
# issues will be displayed without scrolling once more problematic issues are resolved.
|
54
|
+
%i[slows painfuls skips failures brokens errors].each do |issue_category|
|
55
|
+
next unless show?(issue_category, results)
|
56
|
+
|
57
|
+
results.send(issue_category).each { |issue| issue_details(issue) }
|
58
|
+
end
|
59
|
+
rescue StandardError => e
|
60
|
+
message = "Sorry, but Minitest Heat couldn't display the details of any failures."
|
61
|
+
exception_guidance(message, e)
|
62
|
+
end
|
63
|
+
|
45
64
|
def issue_details(issue)
|
46
65
|
print_tokens Minitest::Heat::Output::Issue.new(issue).tokens
|
66
|
+
rescue StandardError => e
|
67
|
+
message = "Sorry, but Minitest Heat couldn't display output for a failure."
|
68
|
+
exception_guidance(message, e)
|
47
69
|
end
|
48
70
|
|
49
71
|
def marker(issue_type)
|
@@ -53,15 +75,49 @@ module Minitest
|
|
53
75
|
def compact_summary(results, timer)
|
54
76
|
newline
|
55
77
|
print_tokens ::Minitest::Heat::Output::Results.new(results, timer).tokens
|
78
|
+
rescue StandardError => e
|
79
|
+
message = "Sorry, but Minitest Heat couldn't display the summary."
|
80
|
+
exception_guidance(message, e)
|
56
81
|
end
|
57
82
|
|
58
83
|
def heat_map(map)
|
59
84
|
newline
|
60
85
|
print_tokens ::Minitest::Heat::Output::Map.new(map).tokens
|
86
|
+
newline
|
87
|
+
rescue StandardError => e
|
88
|
+
message = "Sorry, but Minitest Heat couldn't display the heat map."
|
89
|
+
exception_guidance(message, e)
|
90
|
+
end
|
91
|
+
|
92
|
+
def exception_guidance(message, exception)
|
93
|
+
newline
|
94
|
+
puts "#{message} Disabling Minitest Heat can get you back on track until the problem can be fixed."
|
95
|
+
puts 'Please use the following exception details to submit an issue at https://github.com/garrettdimon/minitest-heat/issues'
|
96
|
+
puts "#{exception.message}:"
|
97
|
+
exception.backtrace.each do |line|
|
98
|
+
puts " #{line}"
|
99
|
+
end
|
100
|
+
newline
|
61
101
|
end
|
62
102
|
|
63
103
|
private
|
64
104
|
|
105
|
+
def no_problems?(results)
|
106
|
+
!results.problems?
|
107
|
+
end
|
108
|
+
|
109
|
+
def no_problems_or_skips?(results)
|
110
|
+
!results.problems? && results.skips.none?
|
111
|
+
end
|
112
|
+
|
113
|
+
def show?(issue_category, results)
|
114
|
+
case issue_category
|
115
|
+
when :skips then no_problems?(results)
|
116
|
+
when :painfuls, :slows then no_problems_or_skips?(results)
|
117
|
+
else true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
65
121
|
def style_enabled?
|
66
122
|
stream.tty?
|
67
123
|
end
|
@@ -82,7 +138,11 @@ module Minitest
|
|
82
138
|
def print_tokens(lines_of_tokens)
|
83
139
|
lines_of_tokens.each do |tokens|
|
84
140
|
tokens.each do |token|
|
85
|
-
|
141
|
+
begin
|
142
|
+
print Token.new(*token).to_s(token_format)
|
143
|
+
rescue
|
144
|
+
puts token.inspect
|
145
|
+
end
|
86
146
|
end
|
87
147
|
newline
|
88
148
|
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
|